Microsoft has fleshed out more details about C# Version 8.0, the next planned major release of the language. C# 8.0 is expected to arrive in 2019, concurrent with the arrival of .Net Core 3.0. Developers can try out language features in betas of the Visual Studio 2019 IDE.
Microsoft said that while most language features in C# 8.0 will run on any version
New features in C# 8.0
Here’s an overview of the most significant features slated for C# 8.0. There are a number of smaller improvements in the works as well, which will trickle out over the coming months.
Nullable reference types
The purpose of this feature is to help prevent the ubiquitous null reference exceptions that have riddled object-oriented programming for half a century now.
It stops you from putting null
into ordinary reference types such as string
– it makes those types non-nullable! It does so gently, with warnings, not errors. But on existing code there will be new warnings, so you have to opt in to using the feature (which you can do at the project, file or even source line level).
string s = null; // Warning: Assignment of null to non-nullable reference type
What if you do want null? Then you can use a nullable reference type, such as string?
:
string? s = null; // Ok
When you try to use a nullable reference, you need to check it for null first. The compiler analyzes the flow of your code to see if a null value could make it to where you use it:
void M(string? s)
{
Console.WriteLine(s.Length); // Warning: Possible null reference exception
if (s != null)
{
Console.WriteLine(s.Length); // Ok: You won't get here if s is null
}
}
The upshot is that C# lets you express your “nullable intent”, and warns you when you don’t abide by it.
Async streams
The async/await feature of C# 5.0 lets you consume (and produce) asynchronous results in straightforward code, without callbacks:
async Task<int> GetBigResultAsync()
{
var result = await GetResultAsync();
if (result > 20) return result;
else return -1;
}
It is not so helpful if you want to consume (or produce) continuous streams of results, such as you might get from an IoT device or a cloud service. Async streams are there for that.
We introduce IAsyncEnumerable<T>
, which is exactly what you’d expect; an asynchronous version of IEnumerable<T>
. The language lets you await foreach
over these to consume their elements, and yield return
to them to produce elements.
async IAsyncEnumerable<int> GetBigResultsAsync()
{
await foreach (var result in GetResultsAsync())
{
if (result > 20) yield return result;
}
}
Ranges and indices
We’re adding a type Index
, which can be used for indexing. You can create one from an int
that counts from the beginning, or with a prefix ^
operator that counts from the end:
Index i1 = 3; // number 3 from beginning
Index i2 = ^4; // number 4 from end
int[] a = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
Console.WriteLine($"{a[i1]}, {a[i2]}"); // "3, 6"
We’re also introducing a Range
type, which consists of two Index
es, one for the start and one for the end, and can be written with a x..y
range expression. You can then index with a Range
in order to produce a slice:
var slice = a[i1..i2]; // { 3, 4, 5 }
Default implementations of interface members
Today, once you publish an interface it’s game over: you can’t add members to it without breaking all the existing implementers of it.
In C# 8.0 we let you provide a body for an interface member. Thus, if somebody doesn’t implement that member (perhaps because it wasn’t there yet when they wrote the code), they will just get the default implementation instead.
interface ILogger
{
void Log(LogLevel level, string message);
void Log(Exception ex) => Log(LogLevel.Error, ex.ToString()); // New overload
}
class ConsoleLogger : ILogger
{
public void Log(LogLevel level, string message) { ... }
// Log(Exception) gets default implementation
}
The ConsoleLogger
class doesn’t have to implement the Log(Exception)
overload of ILogger
, because it is declared with a default implementation. Now you can add new members to existing public interfaces as long as you provide a default implementation for existing implementors to use.
Recursive patterns
We’re allowing patterns to contain other patterns:
IEnumerable<string> GetEnrollees()
{
foreach (var p in People)
{
if (p is Student { Graduated: false, Name: string name }) yield return name;
}
}
The pattern Student { Graduated: false, Name: string name }
checks that the Person
is a Student
, then applies the constant pattern false
to their Graduated
property to see if they’re still enrolled, and the pattern string name
to their Name
property to get their name (if non-null). Thus, if p
is a Student
, has not graduated and has a non-null name, we yield return
that name.
Switch expressions
Switch statements with patterns are quite powerful in C# 7.0, but can be cumbersome to write. Switch expressions are a “lightweight” version, where all the cases are expressions:
var area = figure switch
{
Line _ => 0,
Rectangle r => r.Width * r.Height,
Circle c => Math.PI * c.Radius * c.Radius,
_ => throw new UnknownFigureException(figure)
};
Target-typed new-expressions
In many cases, when you’re creating a new object, the type is already given from context. In those situations we’ll let you omit the type:
Point[] ps = { new (1, 4), new (3,-2), new (9, 5) }; // all Points
Type-related additions to C# 8.0 include:
- The new
Index
type, for indexing. An index can be created from anint
that counts from the beginning or with a prefix^
operator that counts from the end. - The
Range
type, which consists of twoIndex
es, one for the start and one for the end. It can be written with anx..y
range expression; developers then can index with aRange
to produce a slice. - Nullable reference types, to improve code quality, according to the .Net Foundation, which oversees the open source .Net that C# is part of. The feature will add safe reference types in addition to the existing ones that will be called non-nullable. Compilers will warn you when nullable types are dereferenced or when null is values are assigned to non-nullable variable types. The nullable reference type is intended to help developers prevent null reference exceptions. A core of the capability is expressing an intent to be null. The compiler will recognize when something is not null and warn you when you’ve assigned null to a reference that was not declared as null. With the capability, developers get an assist in finding bugs and making them go away.
Other new features planned for C# 8 are:
- Switch expressions, which present a lightweight version of switch statements, in which all cases are expressions.
- Target-typed new expressions, in which the type can be omitted when developers are creating a new object and the type is already given from context.
- Recursive patterns, in which patterns can contain other patterns.
- An opt-in method to deal with code-breaking behavior.
- A default interfaces programming capability, so interfaces can be evolve via virtual extension methods. An API author could add methods to an interface in future versions without breaking source or binary compatibility. The feature already is available in languages such as Java.
- An async streams feature to provide an abstraction that is the asynchronous version of IEnumerable, which is the base interface for nongeneric collections that can be enumerated.
- Extension everything, to provide a way to define new kinds of extension members. Although it is already possible in C# to define methods that act as instance methods of the extended type, the C# 8 proposal expands this capability by supporting static and instance members.
Looking for ASP.NET Core hosting?
While choosing a new web host, make sure you don’t make the same common mistakes that most beginners do. A few of my favorite web hosts are ASPHostPortal, HostForLIFE, UKWindowsHostASP.NET. I recently reviewed ASPHostPortal and in my opinion, they’re the best-shared host out there out of the large lot of hosts I’ve tested. If you’re curious as to why I never had to switch to another host since 2014, give my ASPHostPortal review a read.
A great place to look for a new web host is WebHostingTalk. Their members are very helpful and new members get proper guidance on choosing a web host.