Net 6 что нового

от admin

What’s new in .NET 6 and C# 10. Everything you wanted to know.

This blog post is a compilation of the latest and greatest additions from the .NET 6 release. Also, I’ve created a coding story that will help you to learn new improvements.

Please check the coding story ��:

Source code ��:

⚠�� Please note that the content below consists of excerpts from the actual coding story. Please check the coding story if you haven’t already.

Net 6 что нового

8 ноября компания Microsoft выпустила финальную версию фреймворка .NET 6.0 с C# 10 и F# 6, а также Visual Studio 2022. .NET 6 ознаменовался значительным увеличением поизводительности по сравнению с предыдущими версиями фреймворка и большим количеством нового функционала. Кроме того, это LTS-версия, которая будет поддерживаться в течении следующих трех лет.

.NET 6.0 представляет унифицированную платформу, которая позволяет создавать десктопные и мобильные и веб-приложения, а также приложения для IoT и облака.

.NET 6 и C# 10

Некоторые основные изменения в этой версии:

Благодаря внедрению Dynamic Profile-guided Optimization (PGO) удалось повысить производительность. Dynamic PGO базируется на механизме уровневой компиляции Tiered Compilation, которая позволяет произвести на старте быструю базовую компиляцию методов («уровень 0»), а когда метод потребует, произвести его перекомпиляцию с рядом оптимизаций («уровень 1»)

Полностью переписан API для работы с файлами, в частности, класс FileStream . Это привело к значительному увеличению производительности: увеличилась скорость выполнения и значительно уменьшилось выделение памяти.

Более быстрая проверка интерфейсов и использование их в преобразованиях типов. По данным Microsoft, производительность увеличилась на 16% – 38%.

Добавлены генераторы кода для API System.Text.Json , что опять же повысило производительность и уменьшило выделение памяти. Кроме того, JsonSerializer поддерживает IAsyncEnumerable :

Релиз .NET 6.0 также ознаменовался выходом новой версии языка C# — C# 10. Некоторые из его новвоведений:

Глобальные пространства имен. Достаточно подключить пространство имен в один файл кода с помощью директивы global using , и оно будет доступно во всех файлах проекта.

Пространства имен уровня файла. Так, вместо

Теперь можно создавать объекты record в виде структур (раньше все record представляли классы)

Также вместе с фреймворком вышла новая версия F# — F# 6

.NET 6.0 позволяет использовать Hot Reload для динамческой перезагрузки приложения при изменении кода

Это первая версия фреймворка, которая поддерживает архитектуру Apple Silicon (Arm64) и значительно усовершенствована для работы Windows Arm64.

Некоторые изменения затронули Windows Forms, в частности, возможность установки шрифта для приложения, минимизация кода и ряд других

Добавлен ряд новых API:

Новые API в System.Math , например, SinCos для одновременного вычисления синуса и косинуса и ряд других

API для сжатия для WebSocket

Поддержка прокси для Socks4, Socks4a и Socks5

В Microsoft.Extensions.Hosting добавлено ConfigureHostOptions API

В Microsoft.Extensions.DependencyInjection добавлено CreateAsyncScope API для использования сервисами IAsyncDisposable

В System.Linq методы Enumerable.ElementAt и Enumerable.Take имеют поддержку Index и Range

Также добавлены новые методы DistinctBy/UnionBy/IntersectBy/ExceptBy/MaxBy/MinBy

А в методах FirstOrDefault/LastOrDefault/SingleOrDefault теперь можно установить значение по умолчанию:

Очередь на основе приоритетов — PriorityQueue

Новые структуры для представления дат и времени: DateOnly и TimeOnly

Отмечается, что .NET 6 поддерживается в Visual Studio 2022 и Visual Studio 2022 for Mac. Однако НЕ поддерживается в Visual Studio 2019 и Visual Studio for Mac 8. Кроме того, .NET 6 поддерживается в Visual Studio Code с помощью расширения для C#.

Name already in use

docs / docs / core / whats-new / dotnet-6.md

  • Go to file T
  • Go to line L
  • Copy path
  • Copy permalink
  • Open with Desktop
  • View raw
  • Copy raw contents Copy raw contents

Copy raw contents

Copy raw contents

What’s new in .NET 6

.NET 6 delivers the final parts of the .NET unification plan that started with .NET 5. .NET 6 unifies the SDK, base libraries, and runtime across mobile, desktop, IoT, and cloud apps. In addition to this unification, the .NET 6 ecosystem offers:

Simplified development: Getting started is easy. New language features in C# 10 reduce the amount of code you need to write. And investments in the web stack and minimal APIs make it easy to quickly write smaller, faster microservices.

Better performance: .NET 6 is the fastest full stack web framework, which lowers compute costs if you’re running in the cloud.

Ultimate productivity: .NET 6 and Visual Studio 2022 provide hot reload, new git tooling, intelligent code editing, robust diagnostics and testing tools, and better team collaboration.

.NET 6 will be supported for three years as a long-term support (LTS) release.

Preview features are disabled by default. They are also not supported for use in production and may be removed in a future version. The new xref:System.Runtime.Versioning.RequiresPreviewFeaturesAttribute is used to annotate preview APIs, and a corresponding analyzer alerts you if you’re using these preview APIs.

.NET 6 is supported by Visual Studio 2022 and Visual Studio 2022 for Mac (and later versions).

This article does not cover all of the new features of .NET 6. To see all of the new features, and for further information about the features listed in this article, see the Announcing .NET 6 blog post.

.NET 6 includes numerous performance improvements. This section lists some of the improvements—in FileStream, profile-guided optimization, and AOT compilation. For detailed information, see the Performance improvements in .NET 6 blog post.

The xref:System.IO.FileStream?displayProperty=fullName type has been rewritten for .NET 6 to provide better performance and reliability on Windows. Now, xref:System.IO.FileStream never blocks when created for asynchronous I/O on Windows. For more information, see the File IO improvements in .NET 6 blog post.

Profile-guided optimization (PGO) is where the JIT compiler generates optimized code in terms of the types and code paths that are most frequently used. .NET 6 introduces dynamic PGO. Dynamic PGO works hand-in-hand with tiered compilation to further optimize code based on additional instrumentation that’s put in place during tier 0. Dynamic PGO is disabled by default, but you can enable it with the DOTNET_TieredPGO environment variable. For more information, see JIT performance improvements.

.NET 6 introduces Crossgen2, the successor to Crossgen, which has been removed. Crossgen and Crossgen2 are tools that provide ahead-of-time (AOT) compilation to improve the startup time of an app. Crossgen2 is written in C# instead of C++, and can perform analysis and optimization that weren’t possible with the previous version. For more information, see Conversation about Crossgen2.

The .NET 6 release includes support for macOS Arm64 (or «Apple Silicon») and Windows Arm64 operating systems, for both native Arm64 execution and x64 emulation. In addition, the x64 and Arm64 .NET installers now install side by side. For more information, see .NET Support for macOS 11 and Windows 11 for Arm64 and x64.

Hot reload is a feature that lets you modify your app’s source code and instantly apply those changes to your running app. The feature’s purpose is to increase your productivity by avoiding app restarts between edits. Hot reload is available in Visual Studio 2022 and the dotnet watch command-line tool. Hot reload works with most types of .NET apps, and for C#, Visual Basic, and C++ source code. For more information, see the Hot reload blog post.

.NET Multi-platform App UI (.NET MAUI) is still in preview, with a release candidate coming in the first quarter of 2022 and general availability (GA) in the second quarter of 2022. .NET MAUI makes it possible to build native client apps for desktop and mobile operating systems with a single codebase. For more information, see the Update on .NET Multi-platform App UI blog post.

C# 10 and templates

C# 10 includes innovations such as global using directives, file-scoped namespace declarations, and record structs. For more information, see What’s new in C# 10.

In concert with that work, the .NET SDK project templates for C# have been modernized to use some of the new language features:

  • async Main method
  • Top-level statements
  • Target-typed new expressions
  • File-scoped namespaces
  • Nullable reference types

By adding these new language features to the project templates, new code starts with the features enabled. However, existing code isn’t affected when you upgrade to .NET 6. For more information about these template changes, see the .NET SDK: C# project templates modernized blog post.

F# and Visual Basic

F# 6 adds several improvements to the F# language and F# Interactive. For more information, see What’s new in F# 6.

Visual Basic has improvements in the Visual Studio experience and Windows Forms project startup.

To keep the size of the .NET SDK smaller, some components have been placed in new, optional SDK workloads. These components include .NET MAUI and Blazor WebAssembly AOT. If you use Visual Studio, it will take care of installing any SDK workloads that you need. If you use the .NET CLI, you can manage workloads using the new dotnet workload commands:

Command Description
dotnet workload search Searches for available workloads.
dotnet workload install Installs a specified workload.
dotnet workload uninstall Removes a specified workload.
dotnet workload update Updates installed workloads.
dotnet workload repair Reinstalls all installed workloads to repair a broken installation.
dotnet workload list Lists installed workloads.

Many improvements have been made in xref:System.Text.Json?displayProperty=fullName in .NET 6, such that it is now an «industrial strength» serialization solution.

.NET 6 adds a new source generator for xref:System.Text.Json?displayProperty=fullName. Source generation works with xref:System.Text.Json.JsonSerializer and can be configured in multiple ways. It can improve performance, reduce memory usage, and facilitate assembly trimming. For more information, see How to choose reflection or source generation in System.Text.Json and How to use source generation in System.Text.Json.

A new, writeable document object model (DOM) has been added, which supplements the pre-existing read-only DOM. The new API provides a lightweight serialization alternative for cases when use of plain old CLR object (POCO) types isn’t possible. It also allows you to efficiently navigate to a subsection of a large JSON tree and read an array or deserialize a POCO from that subsection. The following new types have been added to support the writeable DOM:

  • xref:System.Text.Json.Nodes.JsonNode
  • xref:System.Text.Json.Nodes.JsonArray
  • xref:System.Text.Json.Nodes.JsonObject
  • xref:System.Text.Json.Nodes.JsonValue

For more information, see JSON DOM choices.

xref:System.Text.Json?displayProperty=fullName now supports serialization and deserialization with xref:System.Collections.Generic.IAsyncEnumerable%601 instances. Asynchronous serialization methods enumerate any xref:System.Collections.Generic.IAsyncEnumerable%601 instances in an object graph and then serialize them as JSON arrays. For deserialization, the new method xref:System.Text.Json.JsonSerializer.DeserializeAsyncEnumerable%60%601(System.IO.Stream,System.Text.Json.JsonSerializerOptions,System.Threading.CancellationToken)?displayProperty=nameWithType was added. For more information, see IAsyncEnumerable serialization.

New serialization interfaces for validation and defaulting values:

  • xref:System.Text.Json.Serialization.IJsonOnDeserialized
  • xref:System.Text.Json.Serialization.IJsonOnDeserializing
  • xref:System.Text.Json.Serialization.IJsonOnSerialized
  • xref:System.Text.Json.Serialization.IJsonOnSerializing

For more information, see Callbacks.

New property ordering attribute:

New method to write «raw» JSON:

For more information, see Write Raw JSON.

Synchronous serialization and deserialization to a stream:

  • xref:System.Text.Json.JsonSerializer.Deserialize(System.IO.Stream,System.Type,System.Text.Json.JsonSerializerOptions)?displayProperty=nameWithType
  • xref:System.Text.Json.JsonSerializer.Deserialize(System.IO.Stream,System.Type,System.Text.Json.Serialization.JsonSerializerContext)?displayProperty=nameWithType
  • xref:System.Text.Json.JsonSerializer.Deserialize%60%601(System.IO.Stream,System.Text.Json.JsonSerializerOptions)?displayProperty=nameWithType
  • xref:System.Text.Json.JsonSerializer.Deserialize%60%601(System.IO.Stream,System.Text.Json.Serialization.Metadata.JsonTypeInfo<%60%600>)?displayProperty=nameWithType
  • xref:System.Text.Json.JsonSerializer.Serialize(System.IO.Stream,System.Object,System.Type,System.Text.Json.JsonSerializerOptions)?displayProperty=nameWithType
  • xref:System.Text.Json.JsonSerializer.Serialize(System.IO.Stream,System.Object,System.Type,System.Text.Json.Serialization.JsonSerializerContext)?displayProperty=nameWithType
  • xref:System.Text.Json.JsonSerializer.Serialize%60%601(System.IO.Stream,%60%600,System.Text.Json.JsonSerializerOptions)?displayProperty=nameWithType
  • xref:System.Text.Json.JsonSerializer.Serialize%60%601(System.IO.Stream,%60%600,System.Text.Json.Serialization.Metadata.JsonTypeInfo<%60%600>)?displayProperty=nameWithType

New option to ignore an object when a reference cycle is detected during serialization:

For more information about serializing and deserializing with System.Text.Json , see JSON serialization and deserialization in .NET.

.NET 6 includes preview support for HTTP/3, a new version of HTTP. HTTP/3 solves some existing functional and performance challenges by using a new underlying connection protocol called QUIC. QUIC establishes connections more quickly, and connections are independent of the IP address, allowing mobile clients to roam between Wi-fi and cellular networks. For more information, see Use HTTP/3 with HttpClient.

ASP.NET Core includes improvements in minimal APIs, ahead-of-time (AOT) compilation for Blazor WebAssembly apps, and single-page apps. In addition, Blazor components can now be rendered from JavaScript and integrated with existing JavaScript based apps. For more information, see What’s new in ASP.NET Core 6.

.NET 6 brings improved support for OpenTelemetry, which is a collection of tools, APIs, and SDKs that help you analyze your software’s performance and behavior. APIs in the xref:System.Diagnostics.Metrics?displayProperty=fullName namespace implement the OpenTelemetry Metrics API specification. For example, there are four instrument classes to support different metrics scenarios. The instrument classes are:

  • xref:System.Diagnostics.Metrics.Counter%601
  • xref:System.Diagnostics.Metrics.Histogram%601
  • xref:System.Diagnostics.Metrics.ObservableCounter%601
  • xref:System.Diagnostics.Metrics.ObservableGauge%601

.NET 6 adds preview support for two key security mitigations: Control-flow Enforcement Technology (CET) and «write exclusive execute» (W^X).

CET is an Intel technology available in some newer Intel and AMD processors. It adds capabilities to the hardware that protect against some control-flow hijacking attacks. .NET 6 provides support for CET for Windows x64 apps, and you must explicitly enable it. For more information, see .NET 6 compatibility with Intel CET shadow stacks.

W^X is available all operating systems with .NET 6 but only enabled by default on Apple Silicon. W^X blocks the simplest attack path by disallowing memory pages to be writeable and executable at the same time.

Trimming of self-contained deployments is improved. In .NET 5, only unused assemblies were trimmed. .NET 6 adds trimming of unused types and members too. In addition, trim warnings, which alert you to places where trimming may remove code that’s used at run time, are now enabled by default. For more information, see Trim self-contained deployments and executables.

The .NET 6 SDK includes a handful of new code analyzers that concern API compatibility, platform compatibility, trimming safety, use of span in string concatenation and splitting, faster string APIs, and faster collection APIs. For a full list of new (and removed) analyzers, see Analyzer releases — .NET 6.

Custom platform guards

The Platform compatibility analyzer recognizes the Is<Platform> methods in the xref:System.OperatingSystem class, for example, xref:System.OperatingSystem.IsWindows?displayProperty=nameWithType, as platform guards. To allow for custom platform guards, .NET 6 introduces two new attributes that you can use to annotate fields, properties, or methods with a supported or unsupported platform name:

  • xref:System.Runtime.Versioning.SupportedOSPlatformGuardAttribute
  • xref:System.Runtime.Versioning.UnsupportedOSPlatformGuardAttribute

xref:System.Windows.Forms.Application.SetDefaultFont(System.Drawing.Font)?displayProperty=nameWithType is a new method in .NET 6 that sets the default font across your application.

The templates for C# Windows Forms apps have been updated to support global using directives, file-scoped namespaces, and nullable reference types. In addition, they include application bootstrap code, which reduces boilerplate code and allows the Windows Forms designer to render the design surface in the preferred font. The bootstrap code is a call to ApplicationConfiguration.Initialize() , which is a source-generated method that emits calls to other configuration methods, such as xref:System.Windows.Forms.Application.EnableVisualStyles?displayProperty=nameWithType. Additionally, if you set a non-default font via the ApplicationDefaultFont MSBuild property, ApplicationConfiguration.Initialize() emits a call to xref:System.Windows.Forms.Application.SetDefaultFont(System.Drawing.Font).

For more information, see the What’s new in Windows Forms blog post.

The source tarball, which contains all the source for the .NET SDK, is now a product of the .NET SDK build. Other organizations, such as Red Hat, can build their own version of the SDK using this source tarball.

Target framework monikers

Additional OS-specific target framework monikers (TFMs) have been added for .NET 6, for example, net6.0-android , net6.0-ios , and net6.0-macos . For more information, see .NET 5+ OS-specific TFMs.

In preview is the ability to use operators on generic types in .NET 6. .NET 6 introduces numerous interfaces that make use of C# 10’s new preview feature, static abstract interface members. These interfaces correspond to different operators, for example, IAdditionOperators represents the + operator. The interfaces are available in the System.Runtime.Experimental NuGet package. For more information, see the Generic math blog post.

NuGet package validation

If you’re a NuGet library developer, new package-validation tooling enables you to validate that your packages are consistent and well-formed. You can determine if:

  • There are any breaking changes across package versions.
  • The package has the same set of public APIs for all runtime-specific implementations.
  • There are any gaps for target-framework or runtime applicability.

For more information, see the Package Validation blog post.

.NET 6 introduces the following new APIs that inspect code and provide nullability information:

  • xref:System.Reflection.NullabilityInfo?displayProperty=fullName
  • xref:System.Reflection.NullabilityInfoContext?displayProperty=fullName
  • xref:System.Reflection.NullabilityState?displayProperty=fullName

These APIs are useful for reflection-based tools and serializers.

Several extensions namespaces have improvements in .NET 6, as the following table shows.

Namespace Improvements
xref:Microsoft.Extensions.DependencyInjection?displayProperty=fullName xref:Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.CreateAsyncScope%2A lets you safely use a using statement for a service provider that registers an xref:System.IAsyncDisposable service.
xref:Microsoft.Extensions.Hosting?displayProperty=fullName New xref:Microsoft.Extensions.Hosting.HostingHostBuilderExtensions.ConfigureHostOptions%2A methods simplify application setup.
xref:Microsoft.Extensions.Logging?displayProperty=fullName xref:Microsoft.Extensions.Logging?displayProperty=fullName has a new source generator for performant logging APIs. The source generator is triggered if you add the new xref:Microsoft.Extensions.Logging.LoggerMessageAttribute to a partial logging method. At compile time, the generator generates the implementation of the partial method, which is typically faster at run time than existing logging solutions. For more information, see Compile-time logging source generation.

Numerous LINQ methods have been added in .NET 6. Most of the new methods listed in the following table have equivalent methods in the xref:System.Linq.Queryable?displayProperty=fullName type.

Method Description
xref:System.Linq.Enumerable.TryGetNonEnumeratedCount%60%601(System.Collections.Generic.IEnumerable<%60%600>,System.Int32@)?displayProperty=nameWithType Attempts to determine the number of elements in a sequence without forcing an enumeration.
xref:System.Linq.Enumerable.Chunk%60%601(System.Collections.Generic.IEnumerable<%60%600>,System.Int32)?displayProperty=nameWithType Splits the elements of a sequence into chunks of a specified size.
xref:System.Linq.Enumerable.MaxBy%2A?displayProperty=nameWithType and xref:System.Linq.Enumerable.MinBy%2A?displayProperty=nameWithType Finds maximal or minimal elements using a key selector.
xref:System.Linq.Enumerable.DistinctBy%2A?displayProperty=nameWithType, xref:System.Linq.Enumerable.ExceptBy%2A?displayProperty=nameWithType, xref:System.Linq.Enumerable.IntersectBy%2A?displayProperty=nameWithType, and xref:System.Linq.Enumerable.UnionBy%2A?displayProperty=nameWithType These new variations of methods that perform set-based operations let you specify equality using a key selector function.
xref:System.Linq.Enumerable.ElementAt%60%601(System.Collections.Generic.IEnumerable<%60%600>,System.Index)?displayProperty=nameWithType and xref:System.Linq.Enumerable.ElementAtOrDefault%60%601(System.Collections.Generic.IEnumerable<%60%600>,System.Index)?displayProperty=nameWithType Accepts indexes counted from the beginning or end of the sequence—for example, Enumerable.Range(1, 10).ElementAt(^2) returns 9 .
xref:System.Linq.Enumerable.FirstOrDefault%60%601(System.Collections.Generic.IEnumerable<%60%600>,%60%600)?displayProperty=nameWithType and xref:System.Linq.Enumerable.FirstOrDefault%60%601(System.Collections.Generic.IEnumerable<%60%600>,System.Func<%60%600,System.Boolean>,%60%600)?displayProperty=nameWithType
xref:System.Linq.Enumerable.LastOrDefault%60%601(System.Collections.Generic.IEnumerable<%60%600>,%60%600)?displayProperty=nameWithType and xref:System.Linq.Enumerable.LastOrDefault%60%601(System.Collections.Generic.IEnumerable<%60%600>,System.Func<%60%600,System.Boolean>,%60%600)?displayProperty=nameWithType
xref:System.Linq.Enumerable.SingleOrDefault%60%601(System.Collections.Generic.IEnumerable<%60%600>,%60%600)?displayProperty=nameWithType and xref:System.Linq.Enumerable.SingleOrDefault%60%601(System.Collections.Generic.IEnumerable<%60%600>,System.Func<%60%600,System.Boolean>,%60%600)?displayProperty=nameWithType
New overloads let you specify a default value to use if the sequence is empty.
xref:System.Linq.Enumerable.Max%60%601(System.Collections.Generic.IEnumerable<%60%600>,System.Collections.Generic.IComparer<%60%600>)?displayProperty=nameWithType and xref:System.Linq.Enumerable.Min%60%601(System.Collections.Generic.IEnumerable<%60%600>,System.Collections.Generic.IComparer<%60%600>)?displayProperty=nameWithType New overloads let you specify a comparer.
xref:System.Linq.Enumerable.Take%60%601(System.Collections.Generic.IEnumerable<%60%600>,System.Range)?displayProperty=nameWithType Accepts a xref:System.Range argument to simplify taking a slice of a sequence—for example, you can use source.Take(2..7) instead of source.Take(7).Skip(2) .
xref:System.Linq.Enumerable.Zip%60%603(System.Collections.Generic.IEnumerable<%60%600>,System.Collections.Generic.IEnumerable<%60%601>,System.Collections.Generic.IEnumerable<%60%602>)?displayProperty=nameWithType Produces a sequence of tuples with elements from three specified sequences.

Date, time, and time zone improvements

The following two structs were added in .NET 6: xref:System.DateOnly?displayProperty=fullName and xref:System.TimeOnly?displayProperty=fullName. These represent the date part and the time part of a xref:System.DateTime, respectively. xref:System.DateOnly is useful for birthdays and anniversaries, and xref:System.TimeOnly is useful for daily alarms and weekly business hours.

You can now use either Internet Assigned Numbers Authority (IANA) or Windows time zone IDs on any operating system that has time zone data installed. The xref:System.TimeZoneInfo.FindSystemTimeZoneById(System.String)?displayProperty=nameWithType method has been updated to automatically convert its input from a Windows time zone to an IANA time zone (or vice versa) if the requested time zone is not found on the system. In addition, the new methods xref:System.TimeZoneInfo.TryConvertIanaIdToWindowsId(System.String,System.String@) and xref:System.TimeZoneInfo.TryConvertWindowsIdToIanaId%2A have been added for scenarios when you still need to manually convert from one time zone format to another.

There are a few other time zone improvements as well. For more information, see Date, Time, and Time Zone Enhancements in .NET 6.

Что нового в .NET 6?

На момент написания этих строк вышло уже семь превью-версий .NET 6. Дальше — только релиз-кандидаты. Все основные фичи уже добавлены во фреймворк, идёт отладка, тестирование и оптимизация. Ожидать чего-то кардинально нового в RC-версиях, пожалуй, уже не стоит. Пришла пора рассмотреть .NET 6 поближе.

Пресс-релиз для каждой версии содержит огромное количество восхвалений и убеждений в том, что теперь-то всем станет ещё лучше, и как мы вообще жили раньше — уму непостижимо. Где-то авторы не врут, где-то не договаривают, где-то преувеличивают. Пришлось тщательно прочитать все семь пресс-релизов, изучить массу смежных материалов и просмотреть огромное количество тикетов на Гитхабе. Всё для того, чтобы понять, чем они там занимаются и что выкатывают нам посмотреть.

Поговорим об этом.

Производительность

Разработчики .NET всегда делали упор на производительность. С одной стороны, в язык и фреймворк постоянно добавляются новый функционал — ref struct , stackalloc , System.Span<T> и всё такое прочее. С другой стороны, с каждой новой версией .NET добавляются новые оптимизации — многопроходная (tiered) компиляция, компиляция в нативный код и, разумеется, огромное количество оптимизаций, которые делает JIT-компилятор. Грамотное использование этих средств даёт свой эффект, который хорошо видно в реальных боевых условиях на графиках производительности.

В NET 6 представлены три инструмента, которые дают ещё большие возможности для повышения эффективности. Причём, не только для самих приложений, работающих в продакшне, но и для разработчиков. Речь идёт о прокачаной предварительной компиляции (через утилиту Crossgen2), оптимизации на основе профилирования (PGO) и горячей перезагрузке приложений во время отладки.

Предварительная компиляция

Как известно, преимущества JIT-компиляции имеют свою цену. В частности, повышенное время «прогрева» приложения во время старта, поскольку JIT-компилятору требуется перемолоть разом слишком много IL-кода. Эту проблему уже пытались решить компиляцией приложений сразу в нативный код, такая технология уже есть и называется Ready To Run. Но в новой версии фреймворка её значительно переработали.

Старая технология предварительной компиляции была слишком примитивна и позволяла только генерировать нативный код для той платформы, на которой была запущена старая утилита crossgen. Разработчики полностью переписали её с нуля на управляемом коде и назвали Crossgen2. Теперь она предоставляет новые возможности: авторы делают упор на оптимизации, а также использование различных стратегий компиляции для разных платформ (Windows/Linux/macOS/x64/Arm). Всё это достигается новой архитектурой утилиты.

Вкратце это работает так: Crossgen2 разбирает IL-код, составляя некий граф приложения. Затем он запускет внутри себя JIT-компилятор для необходимой платформы, а этот компилятор, анализируя составленный граф, уже создаёт нативный код, применяя при необходимости различные оптимизации. Другими словами, утилита Crossgen2 может быть запущена на платформе x64, но она сгенерирует нативный и даже оптимизтированный код для Arm64. И, разумеется, наоборот это тоже работает.

В настоящий момент код .NET SDK скомпилирован уже с помощью Crossgen2, а старая утилита crossgen отправлена на пенсию.

Оптимизация на основе профилирования

Ещё одна новая старая фишка в .NET 6 — это Profile-Guided Optimization (PGO). Ни для кого не секрет, что обычно в приложении никогда не исполняется вообще весь написанный код. Какой-то код работает чаще других, какой-то вызывается в крайне редких случаях, а какой-то вообще никогда. Но компилятор обычно ничего об этом не знает, а лучше бы знал. Чтобы научить этому компилятор используется PGO-оптимизация. Её смысл заключается в том, что приложение просто прогоняется на разных стандартных кейсах, а заодно профилируется. Итоги профилирования анализируются компилятором, и он начинает распознавать самые часто используемые места кода, уделяя им особое внимание и оптимизируя их более тщательно.

Такое обучение компилятора похоже на обучение нейронной сети. К слову, в некоторых других распространённых языках программирования технология PGO реализована уже давно, но в .NET до этого добрались только сейчас. Эта тема довольно замороченная, и ребята занялись ей очень серьёзно, реализовав несколько различных подходов к компиляции итогового нативного кода.

Один из подходов — разделение на часто и редко используемый код (hot-cold splitting). Те части кода, которые используются наиболее часто (hot code), группируются и помещаются рядом в итоговом бинарнике. Если сильно повезёт, то такой сгруппированный код полностью поместится в кеш процессора, и вызовы различных часто используемых методов будут практически бесплатными и очень быстрыми. Напротив, некий крайне редко используемый код (very cold code) может вообще не быть скомпилирован в нативный. Например, else -ветки, в которых просто выбрасывается исключение. Такой код остаётся в виде IL-кода и будет скомпилирован в нативный уже после запуска приложения и только в том случае, если это будет необходимо. Такое разделение позволяет не только добиться более высокой производительности при старте, но и генерировать бинарники меньшего размера.

Другой подход — динамическая PGO. То есть, все этапы предварительного обучения JIT-компилятора пропускаются, а вместо этого он внимательно смотрит на то, как приложение работает в реальной среде и при необходимости заново компилирует какой-либо участок кода в более оптимальный. Если вы помните, то подобная технология уже существует — это многопроходная (tiered) компиляция (упоминается в начале статьи). Но разработчики JIT-компилятора просто серьёзно её прокачали.

Третий подход — сочетание динамического и статического профилирования для генерации нативного кода. Обе эти техники реализуются одновременно, и итоговый бинарник может частично содержать нативный код для быстрого запуска, который затем может быть оптимизирован ещё больше. В качестве примера приводится ситуация, когда некий интерфейс в программе реализован только в одном классе. В этом случае JIT-компилятор может девиртуализировать вызовы методов интерфейса и сгенерировать код для прямых вызовов методов класса, а также допустить встраивание этих методов прямо в код (inlining), если это будет необходимо.

Техника PGO работает в тесной связке с утилитой Crossgen2 и позволяет генерировать оптимизированный нативный код, а также экономить на размере итоговых бинарников. Но нужно отдавать себе отчёт в том, что статическая PGO — это довольно сложно для обычного разработчика. Ведь ему придётся заниматься многократным профилированием своего кода, результаты которого (а это очень много информации) нужно будет специальным образом подавать на вход при компиляции через Crossgen2. И хорошо, если результаты профилирования в тестовой среде будут пригодны и для продуктивной среды — тогда итоговый профит получить можно. Скажем, приложение будет гораздо быстрее запускаться и прогреваться. Это важный фактор, но надо помнить, что цена такой оптимизации — ресурсы, затраченные на предварительное профилирование, которое должно быть проведено очень аккуратно. Если при прогоне приложения на тестовой среде вы сделаете упор на редкие кейсы (например, тестировщики будут прогонять только негативные сценарии, пытаясь всё сломать), то данные профилирования у вас будут сильно отличаться от боевых. А значит, в итоговом бинарнике у вас предкомпилированным и оптимизированным может оказаться вообще не тот код.

Но, слава богу, есть ещё динамическая PGO, которая не требует предварительных ресурсозатрат и может повышать производительность вашего приложения прямо на лету, причём, делать это более эффективно, чем уже реализовано в существующей многопроходной компиляции. Правда, как вы понимаете, каждый новый рестарт приложения — это всякий раз оптимизация заново.

В общем, выбор у вас есть. Делайте его по ситуации.

Горячая перезагрузка приложений

Эта новая возможность действительно впечатляет. Любому разработчику хочется при отладке быстро пофиксить какой-то мелкий кусок кода без последующей перезагрузки приложения и прохождения заново всего пути к месту отладки. Такая возможность была и раньше, но в очень сильно упрощённом варианте и только в мощной IDE, вроде Visual Studio. Теперь же её прокачали настолько, что она реально позволит сэкономить уйму времени, избавившись от постоянных действий остановка-правка-ребилд-деплой-запуск-достижение точки отладки, причём, в любой IDE, даже в VS Code.

Это работает ещё интереснее, чем вы можете себе представить. Не нужно устанавливать брейкпойнт или ставить приложение на паузу во время отладки. Достаточно просто внести изменения в код и применить их прямо к работающему приложению. В последних билдах Visual Studio это поддерживается легко и просто:

Но даже если вы пользуетесь не студией, а VS Code, то вы не будете ущемлены. Вам нужно просто запустить ваш проект с помощью новой команды dotnet watch . После этого любые изменения в исходных файлах будут автоматически обнаружены, скомпилированы и подгружены в работающее приложение без каких-либо телодвижений с вашей стороны. Вы увидите изменения без его перезагрузки. Проще некуда, и это работает.

В случаях посерьёзнее (например, при отладке приложений ASP.NET) вам придётся добавить настройку в launchSettings.json , разрешающую горячую перезагрузку, что вряд ли станет большой проблемой.

Ложкой дёгтя во всём этом является тот факт, что не всякое изменение можно применить с помощью горячей перезагрузки. Полный список тех действий, которые можно и нельзя перезагрузить по-горячему, можно увидеть здесь.

Ах, да: в F# горячая перезагрузка не поддерживается в принципе. Может, когда-нибудь позже. Просто попросите разработчиков об этом.

Более подробно о горячей перезагрузке написано в переводе на Хабре.

Прочие производительные плюшки

Кроме упомянутых трёх очень важных нововведений в обычном цикле разработки удалось найти массу других мест для оптимизации, ускорив тем самым процесс билда и запуска приложений: ликвидировали причины оверхедов, оптимизировали MSBuild, перевели Razor-компилятор на Roslyn source generator и даже позаботились о том, чтобы пореже трогать файлы и зря беспокоить антивирусное ПО.

В общем, производительность труда разработчиков должна вырасти. По крайней мере, на это намекает диаграмма снижения времени билдов.

Поддержка ОC и платформ

.NET 6 будет поддерживать ещё больше операционок и платформ. Полный список доступен по этой ссылке. Большое внимание уделяется платформе Arm64 в целом: улучшена поддержка Windows Arm64 и добавлена поддержка Arm64-чипов Apple. Что касается последних, то, как известно, эти чипы умеют работать как в нативном режиме, так и в режиме эмуляции x64. .NET 6 будет поддерживать оба режима и будет уметь создавать как обычный x64, так и нативный для Arm64 код. Для разработки под macOS теперь будут два типа проектов: net6.0-macos для x64 и net6.0-maccatalyst для Arm64 архитектур.

Полный список новых Target Framework’ов теперь выглядит так:

  • net6.0
  • net6.0-android
  • net6.0-ios
  • net6.0-maccatalyst
  • net6.0-macos
  • net6.0-tvos
  • net6.0-windows

Однако, с программированием для Apple-устройств есть один нюанс: существует требование, которые предъявляется к приложениям, публикуемым в App Store. Если разработчик приложения хочет, чтобы приложение запускалось как на x64, так и на Arm64 архитектурах, то оно должно быть скомпилировано как Universal Binaries. Вот с этим требованием пока всё плохо: оно просто не поддерживается в .NET 6. В следующей версии .NET 7 разработчики посмотрят, что можно сделать. Впрочем, это не самое критичное требование, пока можно прожить и без него.

В общем, теперь можно брать новые Макбуки.

Также .NET 6 теперь существует для нескольких новых Linux-дистрибутивов: Alpine 3.13, Debian 11 и Ubuntu 20.04 — соответствующие docker-образы создаются с первого превью .NET 6.

Унификация, поглощение Xamarin, «optional workloads» и MAUI

Ещё пару лет назад разработчики .NET объявили, что собираются объединить в одном .NET-флаконе разработку для всего сразу. Ну, то есть, ничего не будет, а будет одно сплошное телевидение один фреймворк для всего, что только есть на свете — и для мобильной, и для серверной, и для веб-разработки, и для IoT, и для… не знаю, что там ещё появится в будущем. И они назвали это .NET 5, перескочив, во-первых, через версию, чтобы не было путаницы с классическим .NET Framework 4.x, а во-вторых, объединив классический фреймворк с Core, к чему стремились с самого начала, просто осторожно шли окольными путями.

В качестве профита от такого объединения упоминались две ключевые фишки:

  • вы пишете на одном языке с использованием одного API;
  • вы не используете то, что вам не надо: новый фреймворк достаточно раздробленный, и вам не нужно устанавливать кучу ненужных библиотек.

Люди, знающие .NET, когда он ещё пешком под стол ходил, в этом месте начинали припоминать, что примерно такие же обещания раздавались налево и направо двадцать лет назад (а потом повторялись с появлением Silverlight и UWP). Классический фреймворк, вроде как, преследовал эти же самые цели, но только был неделимым, как атом, монолитом, заточенным под одну ОС. Однако, мир менялся быстрее и не в ту сторону. Но в MS вовремя опомнились и умудрились запрыгнуть в уходящий поезд, выпустив первую версию Core, да ещё и выведя разработку в Open Source.

Сейчас .NET далеко не в последнем вагоне этого поезда, и, похоже, тотальная унификация действительно не за горами.

Так вот. Пятую версию .NET выпустили, но унификация продолжается: добрались до Xamarin и поглотили его подружили его с .NET 6. Речь идёт, конечно же, о разработке под Android, iOS и macOS. Вообще, вы теперь и без Xamarin имеете возможность набрать команду dotnet new android и начать разрабатывать под Андроид. А запускать разработанное вы будете командой dotnet run . Но я попробовал — это не работает. Такого шаблона проекта даже нет в последней превью-версии .NET 6. Это потому, что соответствующие библиотеки для разработки под Андроид (а также iOS и macOS) — ну, то есть, то, что раньше было частью Xamarin — не являются частью стандартного .NET SDK. Их нужно скачивать отдельно. В первую очередь, это объясняется тем, что не хочется снова создать огромный монолит. В общем, всё постороннее, что пришло вместе с Xamarin, вынесено в «Optional SDK Workloads» — некие дополнительные части фреймворка, не входящие в стандартный SDK. Иначе размер SDK станет неприличным, а сам он начнёт противоречить одной из заявленных целей: не устанавливать кучу ненужного.

Вот этот вот новый «Optional SDK Workloads» теперь является частью .NET 6 и будет продолжать развиваться в .NET 7. Таким образом происходит слияние Xamarin с .NET. Но Xamarin в данном случае не только что-то отдаёт, но и получает взамен: разработка теперь будет вестись с использованием единой BCL, в едином стиле и с едиными подходами, а также можно будет использовать единую систему всех .NET-утилит, начиная с уже упомянутой dotnet new android . Разумеется, делается акцент и на сокращённом времени билда, уменьшении размеров итогового приложения, а таже улучшенной производительности.

Это ещё не всё, что происходит с Xamarin. Анонсировали новый .NET Multiplatform App UI (MAUI) — «эволюция» Xamarin Forms. С этого момента, думаю, про название «Xamarin Forms» можно уже начать забывать. Отныне вся кроссплатформенная UI-разработка будет называться MAUI. Разумеется, по своей сути MAUI — это мультиплатформенная абстракция над различными UI, родными для каждой конкретной платформы. На MAUI можно разработать интерфейсы, которые будут работать и на Blazor, и на мобильных платформах и даже в десктопных приложениях.

Также, скорее всего, можно начать забывать и про Mono, и про сам Xamarin. В шестой версии .NET они пока ещё живы как самостоятельные продукты, но есть подозрение, что седьмая поглотит их окончательно.

А пока разработчики на Xamarin получают возможность полноценно использовать родной .NET 6.0 SDK для кроссплатформенной мобильной разработки.

Как же теперь с этим всем работать, если не получается выполнить команду dotnet new android ? Ну, утилиту dotnet , вообще-то, доработали: для работы с «optional SDK workloads» теперь есть команда dotnet workload . Интересно, что она пока не выводится как доступная при вызове dotnet —help , но пользоваться уже можно:

Никто не мешает вам уже сейчас загрузить нужный дополнительный SDK и попробовать написать небольшой «Hello World» для вашей мобилки. И даже, наверное, без установки Xamarin. Самое приятное: обещают, что можно будет работать с этим в VS Code, не надо будет ставить могучую и неповоротливую полноценную Студию. Желающие могут это сделать прямо сейчас, скачав готовые примеры из репозитория.

Ждём в .NET-разработку притока мобильщиков?

Blazor на десктопе

Оказывается, Blazor стал достаточно популярным (по заверениям разработчиков .NET), причём, настолько, что было решено сделать десктоп-версию Blazor-приложений. Модель разработки это позволяет.

В общем, теперь вы можете написать Blazor-приложение, которое запустится не только в браузере как WebAssembly, но и на Windows и macOS как нативное десктопное.

Улучшения в System.Text.Json

Вот и добрались до изменений в SDK. А их достаточно много, очень сложно пройти мимо. Начнём с System.Text.Json — эту библиотеку очень сильно прокачали.

Игнор цикличных ссылок

В сериализатор добавили опцию игнорирования цикличных ссылок.

Обратите внимание на то, что сериализатор заменяет ссылку на null , а не игнорирует свойство полностью.

Поддержка IAsyncEnumerable<T>

Сериализатор System.Text.Json теперь поддерживает IAsyncEnumerable<T> -объекты. При сериализации он их превращает в массивы:

Для десериализации JSON-документов, которые представляют собой просто массив на корневом уровне, добавили новый удобный метод JsonSerializer.DeserializeAsyncEnumerable :

JSON DOM

Самое интересное нововведение — это возможность работать с JSON-документом как с DOM. Эта особенность довольно полезна, поскольку часто просто не хочется плодить POCO-объекты для простых операций. Вот пример того, как это теперь работает:

До сих пор в подобных случаях нужно было пользоваться классами Utf8JsonWriter / Utf8JsonReader , но DOM-подход тоже неплох.

Поддержка source generators для сериализации

В плане перерасхода ресурсов от DOM-модели не сильно отстаёт обычная сериализация и десериализация. Она основана на рефлексии, а это заведомо медленно. Поэтому там, где реально нужна производительность, всегда лучше было работать с . Writer и . Reader классами (это правило касается не только работы с JSON, но также и с XML). Такая работа занимает больше времени, но окупается максимальной производительностью на продакшне.

Однако разработчики .NET 6 и тут придумали обходной манёвр для облегчения жизни разработчиков: source generators. Эту новую технологию завезли в System.Text.Json , и она решает все основные проблемы, связанные с низкой производительностью обычных сериализаторов: уменьшает время старта приложения и количество используемой памяти, увеличивает скорость работы, не использует рефлексию. Что же тогда используется взамен, если не рефлексия? Именно тот самый класс Utf8JsonWriter , через который и происходит работа с JSON.

Выглядит такая техника точно так же, как и при любой другой работе с source generators. Сначала вы создаёте тип для сериализации/десериализации:

Как видите, он слишком простой, но для иллюстрации работы этого достаточно. Затем вы создаёте partial -класс и сопровождаете его соответствующим атрибутом:

После этого на этапе компиляции ваш частичный класс будет расширен несколькими методами и свойствами:

Через одно из этих свойств — JsonMessage вы получите доступ к сгенерированному сериализатору, работа с которым будет выглядеть как-то так:

Стандартный сериализатор также прокачан и может принимать на вход сгенерированный с помощью source generator код:

Второй способ будет работать чуть-чуть медленнее, но всё равно такая сериализация через генерацию кода будет работать куда быстрее, чем старая сериализация через рефлексию.

Разумеется, сериализация через генерацию кода поддерживает не только примитивные типы, но и объекты (в том числе, вложенные), коллекции и всё остальное.

К сожалению, десериализация через source generators пока не поддерживается. Единственное, что разработчики добавили, — это поддержку в стандартном десериализаторе сгенерированных типов:

Но даже в этом случае никаких Utf8JsonReader не будет. Только рефлексия, только хардкор.

Поддержка нотификаций при (де)сериализации

В специальный неймспейс System.Text.Json.Serialization добавили четыре интерфейса: IJsonOnDeserialized , IJsonOnDeserializing , IJsonOnSerialized и IJsonOnSerializing . Они нужны для вызова методов в процессе (де)сериализации. Как правило, в целях валидации:

Но вы можете придумать и какое-нибудь своё применение.

Порядок следования полей при сериализации

С помощью специального атрибута JsonPropertyOrder теперь можно управлять порядком, в котором сериализованные поля будут помещаться в итоговый JSON:

Ранее порядок, в котором поля попадали в итоговый JSON, был, скажем так, не совсем предсказуем.

Utf8JsonWriter : возможность вывести напрямую JSON-текст

В класс System.Text.Json.Utf8JsonWriter добавили метод WtiteRawValue , и теперь в JSON можно писать raw-текст:

В данном примере решается одна известная проблема сериализатора: он не пишет дробную часть вещественного числа, если она равна нулю. То есть, число 1.1 будет выведено с вещественной частью, а число 1.0 будет выведено как целое. В ряде случаев такое поведение неприемлемо, и теперь вы можете управлять им с помощью нового метода.

Десериализация из Stream

Оказывается, раньше не было возможности десериализовать поток. Теперь есть:

Новая коллекция PriorityQueue

Она представляет собой ту же самую очередь, но каждый элемент которой теперь имеет приоритет. При помещении элемента в очередь вы этот приоритет указываете. При извлечении элемента из очереди сначала извлекаются те элементы, приоритет которых имеет минимальное значение:

Как видно из примера, в случае равенства приоритетов порядок извлечения элементов не гарантирован.

Очень интересная коллекция, вполне подойдёт для некоторых случаев.

Source Generator для ILogger

Новая фича .NET 5 — Source Generators — добралась до логгера. Теперь можно писать меньше кода для логгинга, потому что недостающий код будет создан автоматически. Вам достаточно лишь пометить специальные методы специальным атрибутом LoggerMessageAttribute , и весь недостающий код будет скомпилирован за вас, причём, он будет более оптимальным и производительным.

Только не забудьте пометить и метод, и содержащий его класс ключевым словом partial .

Детали уже можно почитать в документации.

Улучшения в System.Linq

В LinqExtensions добавили массу полезных методов и фич. Например, поддержку диапазонов и индексов. Теперь можно попросить вернуть второй с конца элемент коллекции:

А в метод Take() добавили классную перегрузку:

Новый метод TryGetNonEnumeratedCount() сильно помогает в случаях, когда надо узнать количество элементов коллекции без её перебора:

Если source — это просто переменная типа IEnumerable , то попытка получить количество элементов коллекции может вызывать полный перебор коллекции раньше времени. А с помощью TryGetNonEnumeratedCount() можно и рыбку съесть узнать количество элементов для аллокации соответствующего массива, и полный перебор отложить на более подходящее время.

Четыре новых метода DistinctBy / UnionBy / IntersectBy / ExceptBy теперь позволяют явно указывать поле-селектор:

А в дополнение к ним завезли ещё два аналогичных метода: MaxBy / MinBy .

Странно, что до этого не додумались раньше, но теперь это есть. Методы FirstOrDefault / LastOrDefault / SingleOrDefault позволяют указывать дефолтное значение, как это делается в методе nullable-типов GetValueOrDefault :

Ну и напоследок. Метод Zip теперь имеет перегрузку для итерации по трём коллекциям:

Дата и время

Борьба со временем — это не только метафора из жизни, это ещё и вполне себе реальное явление в мире разработки ПО. Довольно большая часть разработчиков просто не умеет правильно работать с датой и временем. Дополнительного масла в огонь невежества подливают фреймворки, предоставляя вместо правильных инструментов универсальные.

Разработчики .NET решили немного то ли облегчить, то ли усугубить страдания и добавили пару новых структур: DateOnly и TimeOnly , а также немного подшаманили с поддержкой временных зон и ещё по мелочи. Достаточно подробный обзор этих нововведений уже есть в этой переводной статье. И он обязателен к прочтению и глубокому осмыслению.

Preview Features и сразу Generic Math

Выпуск новых версий .NET уже давно встал на поток: в год — по LTS-версии. Это значительно быстрее, чем было раньше с классическим фреймворком, и это хорошо с одной стороны: можно оперативнее реагировать на запросы пользователей, быстрее выкатывать полезные фичи и вообще — не тормозить.

Но внезапно это породило и проблемы с некоторым особенно сложным в разработке функционалом. Разработчики .NET столкнулись с тем, что некоторые полезные новые фичи они физически не успевают выпустить, протестировать и внедрить во всех библиотеках за год. Не говоря уже о том, чтобы собрать фидбек по ним.

И они придумали механизм Preview Features. Теперь LTS-версию .NET можно будет поставлять с недоделанными превью-фичами. То, что раньше было доступно только в превью- и RC-версиях фреймворка, отныне может совершенно легально попасть в библиотеки, компиляторы и продакшн. В целях безопасности это всё обвешано атрибутами и настройками, чтобы по умолчанию быть выключенным. То есть, вы не сможете это использовать, специально не заморочившись. А вот захотите вы заморачиваться или нет — дело ваше.

Возможно, вам понравится первая превью-фича, для которой разработали весь этот механизм: статические абстрактные методы интерфейсов. Эта фича как раз из тех, что довольно сложно внедрить быстро. Её не успели обкатать в превью-версиях .NET 6 и решили выпустить в LTS-версии в том виде, в каком успеют реализовать к релизу. Поскольку это превью-фича, то нет никаких гарантий, что она не изменится даже в ближайших двух RC-выпусках .NET 6. Более того: нет никаких гарантий, что она не изменится в апдейтах .NET 6 после релиза. На этой новой фиче построен механизм арифметики в обобщениях. Детально об этом можно почитать в статье, и звучит это неплохо.

Итого, с помощью нового механизма превью-фич и разработчики .NET, и разработчики на .NET получают лишнее время на обкатку интересных идей. Вопрос: а не выльется ли это в конце концов в то же самое, во что превратились HTML и CSS? Ну, то есть, когда нумерация версий уже не имеет значения, а регулярно добавляемые фичи сначала какое-то время находятся в превью-стадии, а затем, после тестирования и доработок, просто переходят в спецификацию?

Больше анализаторов богу анализа!

С компилятором Roslyn наступила эра Roslyn-анализаторов, которые, вообще-то, здорово помогают в разработке. В .NET 5 в компилятор уже было встроено порядка 250 различных анализаторов, и ещё больше можно было скачать в виде nuget-пакетов. С какого-то момента команда dotnet build выводит дикое количество уведомлений от анализаторов о том, что разработчик говнокодит пишет что-то не то. С одной стороны, эти предупреждения, генерируемые анализаторами, помогают заметить косяки и сделать код чище. С другой стороны, всё равно есть много ложных срабатываний, в которых теряются действительно важные замечания. Это всё можно настроить, но на это нужно время.

В .NET 6 решили не останавливаться на достигнутом, и теперь встроенных анализаторов ещё больше (правда, среди них есть и те, что ранее поставлялись отдельно). Окинув беглым взглядом список новых анализаторов, нельзя не признать, что среди них, безусловно, много полезных.

В общем, читайте портянки компилятора во время вывода и настраивайте свою среду разработки так, чтобы не игнорировать подсказки анализаторов.

API для выделения памяти

Лёгким движением руки C# можно превратить в C. И это почти не шутка: в .NET 6 завезли нативное выделение памяти. За это дело отвечают специальные методы в новом классе System.Runtime.InteropServices.NativeMemory .

К чёрту управляемые ресурсы, к чёрту сборщик мусора. Да здравствуют alloc и free методы! Разумеется, всячески подчёркивается, что это для низкоуровневого кода и алгоритмов. Но мы как-то упустили упустили момент, когда C# стал позиционироваться как язык для таких вещей.

Разработчики очень серьёзно заигрались в оптимизацию. Пока нет единого мнения насчёт того, хорошо это или плохо. Фанаты оптимизаций приветствуют такие возможности. Но людей с определённым профессиональным опытом настораживает попытка создать универсальную платформу для всего сразу.

Что будет дальше? Добавление возможности писать прямые ассемблерные инструкции в коде? Или движение в сторону C++? Подождём .NET 7.

И так далее

Список нововведений в .NET куда больше, чем описано в этой статье. Но надо когда-нибудь остановиться, потому что описать все детали в одном посте — это перебор. Просто быстренько пройдёмся по оставшемуся:

  • пул потоков полностью переписан с нативного на управляемый код;
  • оптимизация работы со структурами: они теперь могут целиком передаваться как параметры через регистры процессора;
  • ускорено приведение и проверка интерфейсных типов (будет быстрее работать Pattern Matching);
  • с помощью прекрасной новой команды dotnet sdk check вы можете проверить актуальность ваших SDK;
  • вебсокеты поддерживают компрессию;
  • BigInteger теперь парсит строки почти на 90% быстрее;
  • Vector<T> теперь поддерживает примитивы nint и nuint ;
  • добавлена поддержка OpenTelemetry.

Но даже это не окончательный список.

А самое главное — за кадром остались нововведения в языке C# 10. Об этом — в другой раз.

Читать:
Как почистить hosts windows 7

Похожие статьи