.NET 5.0 includes many improvements, notably single file applications, smaller container images, more capable JsonSerializer APIs, a complete set of nullable reference type annotations, and support for Windows ARM64.
C# 9 and F# 5 are part of the .NET 5.0 release and included in the .NET 5.0 SDK.
C# Source Generators are an important new C# compiler feature that isn't technically part of C# 9 since it doesn't have any language syntax. See New C# Source Generator Samples to help you get started using this new feature.
C# 9 is a significant release of the language, focused on program simplicity, data immutability, and more patterns. In this post, we'll stick to what might be the crowd favorites.
Top-level programs offer a simpler syntax for programs, with much less ceremony.
The following is the C# 9 version of "hello world".
using System;
Console.WriteLine("Hello World!");
Top-level programs can be extended to use more functionality, such as defining and calling a method or class within the same file.
using System;
using System.Runtime.InteropServices;
Console.WriteLine("Hello World!");
FromWhom();
Show.Excitement("Top-level programs can be brief, and can grow as slowly or quickly in complexity as you'd like", 8);
void FromWhom()
{
Console.WriteLine($"From {RuntimeInformation.FrameworkDescription}");
}
internal class Show
{
internal static void Excitement(string message, int levelOf)
{
Console.Write(message);
for (int i = 0; i < levelOf; i++)
{
Console.Write("!");
}
Console.WriteLine();
}
}
This program produces the following output.
Hello World!
From .NET 5.0.0-preview.8
Top-level programs can be brief, and can grow as slowly or quickly in complexity as you'd like!!!!!!!!
Patterns test that a value has a certain shape, and can extract information from the value when it has the matching shape. New pattern matching improvements have been added in the last few versions of C#.
I'll share two examples. The first demonstrates property patterns. It checks for null (with is) before comparing the context object to a specific pattern.
if (context is {IsReachable: true, Length: > 1 })
{
Console.WriteLine(context.Name);
}
This is equivalent to:
if (context is object && context.IsReachable && context.Length > 1 )
{
Console.WriteLine(context.Name);
}
Also equivalent to:
if (context?.IsReachable && context?.Length > 1 )
{
Console.WriteLine(context.Name);
}
The following example uses relational patterns (like <, <=), and logical ones (like and, or and not). The following code produces the highway toll (as a decimal) for a delivery truck based on its gross weight. For those not familiar, m after a numeric literal tells the compiler, then the number is a decimal and not a double.
DeliveryTruck t when t.GrossWeightClass switch
{
< 3000 => 8.00m,
>= 3000 and <= 5000 => 10.00m,
> 5000 => 15.00m,
},
Target-typed new expressions are a new way to remove type duplication when constructing objects/values.
The following examples are all equivalent, with the new syntax being the middle one.
List<string> values = new List<string>();
List<string> values = new();
var values = new List<string>();
Many people will prefer this new syntax over var
for two reasons.
many people read left-to-right and want the type information on the left-hand side of =, and (likely more importantly) the left side is solely dedicated to type information and not distracted by the complexity or nuance of a particular constructor (on the right-hand side).
Building on updates to the F# 5 preview released earlier this year, this final update to F# 5 wraps up language support. It adds two new features, Interpolated Strings, and Open Type Declarations. Here's a sneak peek at what you can do with them:
Interpolated strings in F# are one of the most highly-requested features. People familiar with them in C# and JavaScript have come to love them in those languages.
In F#, the interpolated strings are introduced in an untyped fashion as they exist in other languages, but also with typed interpolated holes where the expression in an interpolated context must match a type given by a string format specifier.
// Basic interpolated string
let name = "Phillip"
let age = 29
let message = $"Name: {name}, Age: {age}"
// Typed interpolation
// '%s' requires the interpolation to be of type string
// '%d' requires the interpolation to be an integer
let message2 = $"Name: %s{name}, Age: %d{age}"
Open Type Declarations in F# are similar to the ability to open static classes in C#, but with a slightly different syntax. They are also extended to allow opening F# specific types.
open type System.Math
let x = Min(1.0, 2.0)
module M =
type DU = A | B | C
let someOtherFunction x = x + 1
// Open only the type inside the module
open type M.DU
printfn "%A" A
Stay tuned for a blog post that goes over the details.
Here are some of the improvements to the runtime diagnostic tools.
The team has made improvements to the console log provider in the Microsoft.Extensions.Logging
library.
ConsoleFormatter
to exercise complete control over formatting and colorizing the console output.Besides, to support custom formatters, a built-in JSON formatter is also added that emits structured JSON logs to the console.
Debugging managed code requires special knowledge of managed objects and constructs. The Data Access Component (DAC) is a subset of the runtime execution engine that has knowledge of these constructs and can access these managed objects without a runtime.
dotnet dump analyze
.In Preview 8, the support for capturing ELF dumps from .NET processes running on macOS is also added. a
COMPlus_DbgEnableElfDumpOnMacOS=1
.dotnet dump analyze
.The assembly load information is added to the event pipe. You can think of this as a replacement for the Fusion Log Viewer. You can now use dotnet-trace to collect this information, using the following command:
dotnet-trace collect --providers Microsoft-Windows-DotNETRuntime:4:4 --process-id [process ID]
The workflow is described in Trace Assembly Loading with Event Pipe.
As .NET has extended support for new operating systems and chip architectures, people sometimes want a way to print environment information. We created a simple .NET tool that does this, called dotnet-runtimeinfo.
You can install and run the tool with the following commands.
dotnet tool install -g dotnet-runtimeinfo
dotnet-runtimeinfo
The tool produces output in the following form for your environment.
.NET information
Version: 5.0.0
FrameworkDescription: .NET 5.0.0-preview.8.20407.11
Libraries version: 5.0.0-preview.8.20407.11
Libraries hash: bf456654f9a4f9a86c15d9d50095ff29cde5f0a4
**Environment information
OSDescription: Linux 5.8.3-2-MANJARO-ARM #1 SMP Sat Aug 22 21:00:07 CEST 2020
OSVersion: Unix 5.8.3.2
OSArchitecture: Arm64
ProcessorCount: 6
**CGroup info
cfs_quota_us: -1
memory.limit_in_bytes: 9223372036854771712
memory.usage_in_bytes: 2945581056
Many new APIs were added and improved in .NET 5.0. The following are important changes.
Nullable reference types were an important feature of C# 8 and .NET Core 3.0. It was released with a lot of promise but was missing exhaustive platform annotations to make it truly useful and practical.
The team has invested a lot to improve the Regex engine. With these improvements, the throughput is improved by 3-6x, and in some cases, much more. The changes we’ve made in System.Text.RegularExpressions have had a measurable impact on our uses, and we hope these improvements will result in measurable wins in your libraries and apps, as well.