Readonly members
You can apply the readonly
modifier to members of a struct. It indicates that the member doesn’t modify state. It’s more granular than applying the readonly
modifier to a struct
declaration.
Default interface methods
You can now add members to interfaces and provide an implementation for those members. This language feature enables API authors to add methods to an interface in later versions without breaking source or binary compatibility with existing implementations of that interface. Existing implementations inherit the default implementation. This feature also enables C# to interoperate with APIs that target Android or Swift, which support similar features. Default interface methods also enable scenarios similar to a “traits” language feature.
More patterns in more places
Pattern matching gives tools to provide shape-dependent functionality across related but different kinds of data. C# 7.0 introduced syntax for type patterns and constant patterns by using the is
expression and the switch
statement. These features represented the first tentative steps toward supporting programming paradigms where data and functionality live apart. As the industry moves toward more microservices and other cloud-based architectures, other language tools are needed.
C# 8.0 expands this vocabulary so you can use more pattern expressions in more places in your code. Consider these features when your data and functionality are separate. Consider pattern matching when your algorithms depend on a fact other than the runtime type of an object. These techniques provide another way to express designs.
In addition to new patterns in new places, C# 8.0 adds recursive patterns. The result of any pattern expression is an expression. A recursive pattern is simply a pattern expression applied to the output of another pattern expression.
Using declarations
A using declaration is a variable declaration preceded by the using
keyword. It tells the compiler that the variable being declared should be disposed at the end of the enclosing scope.
Static local functions
You can now add the static
modifier to local functions to ensure that local function doesn’t capture (reference) any variables from the enclosing scope. Doing so generates CS8421
, “A static local function can’t contain a reference to <variable>.”
Disposable ref structs
A struct
declared with the ref
modifier may not implement any interfaces and so can’t implement IDisposable. Therefore, to enable a ref struct
to be disposed, it must have an accessible void Dispose()
method. This feature also applies to readonly ref struct
declarations.
Nullable reference types
Inside a nullable annotation context, any variable of a reference type is considered to be a nonnullable reference type. If you want to indicate that a variable may be null, you must append the type name with the ?
to declare the variable as a nullable reference type.
For nonnullable reference types, the compiler uses flow analysis to ensure that local variables are initialized to a non-null value when declared. Fields must be initialized during construction. The compiler generates a warning if the variable isn’t set by a call to any of the available constructors or by an initializer. Furthermore, nonnullable reference types can’t be assigned a value that could be null.
Nullable reference types aren’t checked to ensure they aren’t assigned or initialized to null. However, the compiler uses flow analysis to ensure that any variable of a nullable reference type is checked against null before it’s accessed or assigned to a nonnullable reference type.
Asynchronous streams
Starting with C# 8.0, you can create and consume streams asynchronously. A method that returns an asynchronous stream has three properties:
- It’s declared with the
async
modifier. - It returns an IAsyncEnumerable<T>.
- The method contains
yield return
statements to return successive elements in the asynchronous stream.
Consuming an asynchronous stream requires you to add the await
keyword before the foreach
keyword when you enumerate the elements of the stream. Adding the await
keyword requires the method that enumerates the asynchronous stream to be declared with the async
modifier and to return a type allowed for an async
method. Typically that means returning a Task or Task<TResult>. It can also be a ValueTask or ValueTask<TResult>. A method can both consume and produce an asynchronous stream, which means it would return an IAsyncEnumerable<T>.
Indices and ranges
Indices and ranges provide a succinct syntax for accessing single elements or ranges in a sequence.
This language support relies on two new types, and two new operators:
- System.Index represents an index into a sequence.
- The index from end operator
^
, which specifies that an index is relative to the end of the sequence. - System.Range represents a sub range of a sequence.
- The range operator
..
, which specifies the start and end of a range as its operands.
Let’s start with the rules for indexes. Consider an array sequence
. The 0
index is the same as sequence[0]
. The ^0
index is the same as sequence[sequence.Length]
. Note that sequence[^0]
does throw an exception, just as sequence[sequence.Length]
does. For any number n
, the index ^n
is the same as sequence.Length - n
.
A range specifies the start and end of a range. The start of the range is inclusive, but the end of the range is exclusive, meaning the start is included in the range but the end isn’t included in the range. The range [0..^0]
represents the entire range, just as [0..sequence.Length]
represents the entire range.
Null-coalescing assignment
C# 8.0 introduces the null-coalescing assignment operator ??=
. You can use the ??=
operator to assign the value of its right-hand operand to its left-hand operand only if the left-hand operand evaluates to null
.
Unmanaged constructed types
In C# 7.3 and earlier, a constructed type (a type that includes at least one type argument) can’t be an unmanaged type. Starting with C# 8.0, a constructed value type is unmanaged if it contains fields of unmanaged types only.
Stackalloc in nested expressions
Starting with C# 8.0, if the result of a stackalloc expression is of the System.Span<T> or System.ReadOnlySpan<T> type, you can use the stackalloc
expression in other expressions.
Enhancement of interpolated verbatim strings
Order of the $
and @
tokens in interpolated verbatim strings can be any: both $@"..."
and @$"..."
are valid interpolated verbatim strings. In earlier C# versions, the $
token must appear before the @
token.
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.0</TargetFramework>
</PropertyGroup>
</Project>
The
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.0</TargetFramework>
</PropertyGroup>
<PropertyGroup>
<LangVersion>8.0</LangVersion>
</PropertyGroup>
</Project>
- preview
- latest
- latestMajor
- 8.0
- 7.3
- 7.2
- 7.1
- 7, 6, 5, 4, and 3