This document lists known breaking changes in Roslyn in C# 9.0 which will be introduced with .NET 5 (Visual Studio 2019 version 16.8).
-
Beginning with C# 9.0, when you switch on a value of type
byte
orsbyte
, the compiler tracks which values have been handled and which have not. Technically, we do so for all numeric types, but in practice it is only a breaking change for the typesbyte
andsbyte
. For example, the following program contains a switch statement that explicitly handles all of the possible values of the switch's controlling expressionint M(byte b) { switch (b) { case 0: case 1: case 2: ... return 0; } return 1; }
Since it returns from the method
M
on every value of the input, the following statement (return 1;
) is considered not to be reachable and will produce a warning for unreachable code. Previously, the compiler did not analyze the set of values for completeness, and the following statement was considered reachable. This code compiles without warnings in C# 8.0 but will produce a warning in C# 9.0.Similarly, a switch expression that explicitly handles all values of an input of type
byte
orsbyte
is considered to be complete. For example, the following programint M(byte b) { return b switch { 0 => 0, 1 => 0, 2 => 0, ... byte.MaxValue => 0, }; }
Would produce a warning when compiled in C# 8.0 (the switch expression does not handle all values of its input), but produces no warning in C# 9.0. Conversely, adding a fallback branch to it would suppress the warning in C# 8.0, but cause an error in C# 9.0 (the case is handled by previous cases):
int M(byte b) { return b switch { 0 => 0, 1 => 0, 2 => 0, ... byte.MaxValue => 0, _ => 1 // error in C# 9.0 }; }
-
not
as a type in a pattern not permitted in C# 9.0 In C# 9.0 we introduce anot
pattern that negates the following pattern:bool IsNull(object o) => o is not null;
We recommend the pattern
not null
as the most clear way to check if a value is not null.Because a pattern in C# 9.0 can start with
not
as part of the pattern, we no longer consider a pattern that starts withnot
to be referencing a type namednot
. The expressiono is not x
used to declare a variablex
of typenot
. Now, it checks that the inputo
is not the same as the constant namedx
. -
and
andor
are not permitted as a pattern designator in C# 9.0 In C# 9.0, we introduceand
andor
pattern combinators that combine other patterns:bool IsSmall(int i) => o is 0 or 1 or 2;
We also introduce type patterns so that you do not have to have an identifier naming the variable you are declaring:
bool IsSignedIntegral(object o) => o is sbyte or short or int or long;
Because the
and
andor
combinators can follow a type pattern, the compiler interprets them as part of the pattern combinator rather than an identifier for the declaration pattern. Consequently, it is an error to useor
orand
as pattern variable identifiers starting with C# 9.0. -
#44841 In C# 9 and onwards the language views ambiguities between the
record
identifier as being either a type syntax or a record declaration as choosing the record declaration. The following examples will now be record declarations:abstract class C { record R2() { } abstract record R3(); }
-
The fix for #44067 generates correct (different) code. In certain cases the compiler used to generate code whose behavior was ambiguous according to the CLR's specification. The compiler used to produce the warning CS1957 in those cases. The compiler now generates correct unambiguous code rather than reporting CS1957. Because it is possible that the runtime behavior of a program will change due to the change in our code generation strategy, this could be a breaking change. If your program did not elicit the warning CS1957 before then this does not affect your code.