It’s safe to say that Microsoft is implementing its plans to create a single platform for developing applications for any device and operating system. The latest version of the .NET platform (called .NET 6) confirms that company is moving in this direction. This article talks about the most interesting and useful innovations that were released as part of the latest major update.
C# 10
Mads Torgersen, who has been developing the platform for over 15 years, said in an interview that in C# 10, they were more focused on improving existing functionality than adding major new features. The key focus in this version of the language is on simplicity.
Global using directive
Now, you can use one using directive for the entire project. To do this, you must use the added global keyword before the phrase:
global using your_namespace;
Please note that you should declare a global directive BEFORE use includes that declare without using globals.
Example:
// Correct
global using System.Text;
using System;
using System.Linq;
// Error CS8915
// A global using directive must precede
// all non-global using directives.
using System;
global using System.Text;
using System.Linq;
File scoped namespace
As mentioned above, Microsoft is moving towards simplifying the syntax. This policy also applies to namespace entries.
// Before
using System;
namespace MyNamespace
{
public class MyClass { }
}
// Now
using System;
namespace MyNamespace;
public class MyClass { }
This solves the problem of shifting text indents when you need to use the namespace throughout the file.
Constant interpolated strings
Previously, this feature was not supported, but now constant strings can also be interpolated:
const string firstConstStr = "firstConstStr";
const string secondConstStr = $"secondConstStr {firstConstStr}";
Structure changes
Now, you can set the initialization of fields and properties in structures. Also, it is now possible to create a constructor without parameters for structures.
public struct User
{
public User()
{
}
public User(string name, int age)
{
Name = name;
Age = age;
}
string Name { get; set; } = string.Empty;
int Age { get; set; } = 18;
}
Hot reload
Now, we can modify an app’s source code and instantly apply those changes to the running app.
No need to set a breakpoint or pause the application while debugging. It is enough just to make changes to the code and apply them directly to the running application. In the latest builds of Visual Studio, this is supported simply and easily.
It’s the same with Visual Studio Code. You just need to start your project with the new dotnet watch command. After that, any changes in the source files will be automatically detected, compiled, and loaded into the running application.
Hot reload works with many popular types of applications, such as Windows Forms, ASP.NET Core, Blazor, Console Application, Azure Functions, WPF, .NET MAUI, WinUI 3, and others.
System.Text.Json APIs
So, we’ve got to the changes in the SDK. And there are a lot of them, especially with System.Text.Json—this library has been heavily pumped. I will present a few of them.
IAsyncEnumerable support
The System.Text.Json serializer now supports IAsyncEnumerable objects. When serialized, it turns them into arrays:
static async IAsyncEnumerable PrintNumbers(int n)
{
for (int i = 0; i < n; i++)
yield return i;
}
using Stream stream = Console.OpenStandardOutput();
var data = new { Data = PrintNumbers(3) };
await JsonSerializer.SerializeAsync(stream, data); // prints {"Data":[0,1,2]}
JsonSerializer.DeserializeAsyncEnumerable
To deserialize JSON documents, which are just an array at the root level, a new convenient method, JsonSerializer.DeserializeAsyncEnumerable, has been added:
var stream = new MemoryStream(Encoding.UTF8.GetBytes("[0,1,2,3,4]"));
await foreach (int item in JsonSerializer.DeserializeAsyncEnumerable(stream))
{
Console.WriteLine(item);
}
Support for source generators for serialization
Standard serialization and deserialization is based on reflection, which is notoriously slow. Therefore, where performance is really needed, it has always been better to work with …Writer and …Reader classes (this rule applies not only to working with JSON, but also with XML). Such work takes more time, but pays off with maximum productivity in production.
However, things get easier when we use source generators. Source generators are extensions to the compiler that allow you to add some of your fragments to the compiled code at the time of compilation. This new technology has been brought into System.Text.Json, and it solves all the main problems associated with the low performance of standard serializers: it reduces the application start time and the amount of memory used, increases the speed of work, and does not use reflection.
Deserializing from a Stream
Previously it was not possible to deserialize a stream. Now, we can do it like this:
using MemoryStream ms = GetSomeStream();
MyData md = JsonSerializer.Deserialize(ms);
.NET MAUI
.NET Multi-Platform App User Interface (MAUI) is a technology that allows us to build native desktop and mobile apps with a single code base. It can be said that .NET MAUI is the evolution of Xamarin.
This feature combines the Android, iOS, macOS, and Windows operating system APIs into one single API that allows you to write one common code for all supported operating systems and, if necessary, add platform-specific functionality for each individual platform.
MAUI benefits:
- One code base for all platforms.
- MAUI provides direct access to the native APIs of each platform, including the hardware capabilities of the platforms.
- When you create an application, you can use the .NET platform and the C# programming language (as well as F#), which is quite a productive approach, and at the same time clear and easy to learn, and use MAUI.
- Rich collection of built-in controls.
- Data-binding support.
- Ability to customize the behavior of the visual interface and built-in functionality.
- Rich graphics options.
- Hot reload, which simplifies development.
- .NET MAUI reached General Availability status in May 2022. Telerik UI, DevExpress, Syncfusion, and others have already presented their solutions that expend MAUI.
Improvements in System.Linq
A lot of useful methods and features have been added to LinqExtensions. For example, support for ranges and indexes. Now we can get a second element from the end of the collection:
Enumerable.Range(1, 10).ElementAt(^2); // returns 9
q.Take(..3); // instead of q.Take(3)
q.Take(3..); // instead of q.Skip(3)
q.Take(2..7); // instead of q.Take(7).Skip(2)
q.Take(^3..); // instead of q.TakeLast(3)
q.Take(..^3); // instead of q.SkipLast(3)
q.Take(^7..^3); // instead of q.TakeLast(7).SkipLast(3)
Enumerable.Empty().SingleOrDefault(-1); // returns –1
List buffer = source.TryGetNonEnumeratedCount(out int count) ?
new List(capacity: count) : new List();
foreach (T item in source)
{
buffer.Add(item);
}
Precompilation (Crossgen2)
Crossgen is a tool that provides ahead-of-time (AOT) compilation for your code so that the need for JITing at runtime is reduced. The .NET SDK code is now compiled with Crossgen2, and the old Crossgen utility also has been replaced by the new one.
The benefits of JIT compilation have come at a cost. In particular, increased application startup time, because the JIT compiler needs to process too much IL code. Efforts have already been taken to solve this problem by compiling applications directly into native code—this technology already exists and is called Ready To Run. But in the new version of the framework, it has been significantly reworked.
The old pre-compilation technology was too primitive and only allowed you to generate native code for the platform on which the old Crossgen utility was run. The developers have completely rewritten it from scratch in managed code and named it Crossgen2. Now, it provides new features: the authors persistently use different compilation strategies for different platforms (Windows/Linux/macOS/x64/Arm). All this is covered by the new architectural utility.
Here’s how it works. Crossgen2 parses the IL code, making up a kind of application graph. Then it launches inside itself a JIT compiler for the required platform. This compiler creates native code by analyzing the compiled graph and applying various optimizations if necessary. The Crossgen2 utility can be run on the x64 platform, but it will generate native and even optimized code for Arm64.
.NET 6 new features—takeaway
These are only some of the .NET framework innovations introduced recently. To get the complete picture, you can check the full list of new .NET features.
But the best way to get started with .NET 6 is to download Visual Studio 2022, which is compatible with the new version of the framework, and select the project template you are interested in. Enjoy programming!