Microsoft has released .NET 10, a long-term support (LTS) version that will remain relevant until November 10, 2028. The platform has received significant performance improvements across all components, from the runtime and programming languages to system libraries and build tools.
Microsoft also advises developers to migrate to .NET 10 to enhance performance and reduce application energy consumption. To facilitate migration, GitHub Copilot can be used to adapt existing code and update dependencies.
The release of .NET 10 has not brought about a revolution but rather a host of targeted, mature improvements. The development team has clearly focused on "polishing": fewer experimental features and more emphasis on performance, usability, and API cleanliness. This article highlights the key points.
Â
Â
The new version of the language makes the syntax more flexible without sacrificing readability.
Properties with field. You can now write custom get/set methods, accessing the backing field through the contextual keyword field. No need for extra fields manually.
public string Name { get => field; set => field = value.Trim(); }
Â
Starting with C# 14, the nameof argument can be an unrelated generic type. For example, nameof(List<>) returns List. In earlier versions of C#, to get the name of List<int> only closed generic types like List could be used.
Â
The change will help make the code more optimized with less effort. C# has learned to perform more implicit conversions to make it easier for us to use Span in our work.Â
Span is a type that allows for efficient memory management. It essentially creates a "window" through which we interact with memory. Additionally, Span prevents any out-of-bounds access to the allocated memory window, which could occur with unsafe access. It will check itself and throw an error if the index goes out of bounds.
C# 14 recognizes the relationship and supports certain conversions between ReadOnlySpan<T>, Span<T> and T[]. Span types can act as recipients for extension methods, be combined with other conversions, and assist in situations involving the inference of generic types.
Parameters like ref, in, and out can now be specified even in short lambdas:
var tryParse = (ref int x) => int.TryParse("42", out x);
The new solution will allow us to focus on code development rather than repeatedly describing standard procedures. This will be especially relevant for out parameters.
Â
Previously, C# 13 allowed the use of partial for properties and indexers. In the new version, partial can be used to split constructors and events.Â
The greatest benefit from partial functions will be gained by library creators and code generation tools. Partial events will be especially useful for libraries that support weak events, while partial constructors will be beneficial for platforms generating compatible code.
It is important to note that, unlike methods, which can only be declared, partial constructors and events must have a complete implementation.
This is an optimization feature that expands the capabilities of operator overloading in the programming language. It allows for the overloading of not only unary and binary operators but also compound operators such as +=, *= and others. Since the implementation of these operators has much in common, the following text will focus on the  += operator. However, all conclusions drawn for it will also apply to similar operators.
It is important to note that when using the += in C# 13, the overloaded + operator is called first, and then the result is assigned.
When working with value types, overloading the + operator results in additional copying of both operands and the creation of a new instance as a result. While this behavior is expected, it can lead to unnecessary overhead in copying and processing data, especially when dealing with large types such as mathematical vectors and tensors.
Â
Â
No need to convert DateOnly to DateTime just to get the week number, which is relevant for business applications with intensive date processing.
public static class ISOWeek { public static int GetWeekOfYear(DateOnly date); public static int GetYear(DateOnly date); public static DateOnly ToDateOnly(int year, int week, DayOfWeek dayOfWeek); }
Â
The archive update mode no longer loads everything into memory. Extraction is parallelized, which is especially noticeable with large ZIP files.
Â
Â
Certificate search by thumbprint has become safer thanks to the new FindByThumbprint method, which allows for the explicit specification of a modern hashing algorithm (e.g., SHA-256), moving away from the outdated SHA-1.
Â
The handling of PEM files has been optimized for working with UTF-8 byte representations. The new PemEncoding.FindUtf8 method eliminates the need to convert bytes to a string, reducing memory consumption and speeding up parsing.
// Before .NET 10 byte[] fileContents = File.ReadAllBytes(path); char[] text = Encoding.ASCII.GetString(fileContents); PemFields pemFields = PemEncoding.Find(text); Â // .NET 10 byte[] fileContents = File.ReadAllBytes(path); PemFields pemFields = PemEncoding.FindUtf8(fileContents);
Â
Â
The main innovation is improved support for asynchronous operations. The API for displaying forms and dialogs, which was experimental in .NET 9 and required disabling the compiler warning WFO5002, is now fully stable and ready for use without any additional configuration. The methods Form.ShowAsync, Form.ShowDialogAsync, and TaskDialog.ShowDialogAsync allow for the creation of a truly responsive interface without blocking, especially when working with multiple windows.
Â
In .NET 10, the missing editor types related to UITypeEditor have been integrated into the platform from .NET Framework. They are now available when working with PropertyGrid and the designer action panel. Additionally, the functionality of SnapLines for custom designers has been fixed.
Â
In response to modern security requirements, an API has been added to prevent unwanted screen recording. The Form.ScreenCaptureMode property allows for flexible control over the visibility of the form during capture: it can hide the content, completely blur the window, or leave everything as is. This is especially relevant for applications that handle sensitive data.
Â
Â
A key performance improvement has been made to the CollectionView and CarouselView controls on iOS and Mac Catalyst. The optimized handlers, which were available as an optional feature in .NET 9, are now enabled by default. This provides higher speed and stability when displaying complex lists with custom templates, reducing resource consumption.
It now uses optimized handler by default.
Â
The HybridWebView component has received several significant improvements for tighter integration of web code and .NET:
Lifecycle Events — The events WebViewInitializing and WebViewInitialized have been introduced, allowing for configuration of the web view at the platform level before and after its creation.
Â
A significant new feature is the ability to intercept requests within BlazorWebView and HybridWebView. Developers can modify headers, redirect traffic, or replace responses, which opens up wide possibilities for caching, security, and local data processing.
{ if (e.Uri.ToString().Contains("api/secure")) { e.Handled = true; e.SetResponse(200, "OK", "application/json", GetCustomStream()); } };
Â
Â
In Blazor applications, streaming responses for HttpClient are now enabled by default. This means that the method response.Content.ReadAsStreamAsync() returns BrowserHttpReadStream instead of MemoryStream, which reduces memory consumption but requires attention when using synchronous operations.
To preserve the previous behavior, there are options to disable it:
<WasmEnableStreamingResponse>false</WasmEnableStreamingResponse>
HttpRequestMessage.SetBrowserResponseStreamingEnabled(false)
Â
In .NET 10, the loading of framework resources has been improved for both models of Blazor applications:
OverrideHtmlAssetPlaceholders to true and add the <link rel="preload" id="webassembly" /> in the <head>.Â
Now developers can not only invoke functions but also fully interact with objects and their properties:
These capabilities are available in both asynchronous (IJSRuntime), and synchronous (IJSInProcessRuntime) modes, opening new scenarios for tight integration of .NET and JavaScript code in hybrid and Blazor applications.
// Example of creating an instance of a JS class and working with it var classRef = await JSRuntime.InvokeConstructorAsync("jsInterop.TestClass", "Blazor!"); var text = await classRef.GetValueAsync<string>("text"); var textLength = await classRef.InvokeAsync<int>("getTextLength");
Â
Â
.NET 10 is a release without any "wow" factors, but with deep polishing. The language is more expressive, WinForms has a modernized look, MAUI is more stable, and Blazor is getting even closer to offering that “native” browser experience. Upgrading is definitely worth it, even if you’re not chasing the latest features: the fixes for legacy issues and memory optimizations are well worth it on their own.