>
>
>
Что нового в .NET 9?

Артём Ровенский
Статей: 23

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

.NET 9 вышел в релиз, и значит, можно начинать переносить свои проекты на новую версию. В этой статье мы рассмотрим новые улучшения и фишки .NET: C# 13, производительность, BuildCheck, GC, LINQ, NuGet Audit и прочее.

.NET 9 сфокусирован на облачных приложениях и производительности. Это standard-term support (STS) релиз, который будет поддерживаться полтора года.

По большей части эта статья расскажет про самые интересные улучшения в библиотеках, Runtime и SDK. Мне просто не хватит одной публикации, чтобы рассказать про изменения ещё и в ASP.NET Core, .NET MAUI, .NET Aspire, Entity Framework Core и WPF.

C# 13

Мы уже прошлись по всем нововведениям C# 13 в отдельной статье. Там мы затронули новые особенности языка: partial свойства и индексаторы, params коллекции, новый класс Lock, инициализацию объекта по индексу "от конца" и многое другое. Радует, что изменений в C# в этом году больше, чем в прошлом, хоть и не все они одинаково полезны. А как вы оцениваете обновление языка? Мы вот взглянули, и сразу появились идеи для новых правил C# анализатора.

Как обычно, наша команда уже работает над поддержкой нового .NET. Поддержка .NET 9 и C# 13 появится в PVS-Studio 7.34. Релиз запланирован на начало декабря, и чтобы его не пропустить, приглашаю подписаться на рассылку пресс-релизов.

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

С каждым выходом нового .NET Стивен Тауб выпускает ОГРОМНУЮ статью. В ней он рассказывает про улучшения производительности в .NET. Этот раз не исключение. Автор описывает усовершенствования в различных частях .NET и подкрепляет всё это бенчмарками. Конечно, улучшения коснулись JIT, GC, Native AOT, различных типов данных, рефлексии, LINQ и ещё десятка вещей.

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

Библиотеки

LINQ

В .NET 9 были добавлены в System.Linq методы CountBy, AggregateBy и Index.

Новый тип OrderedDictionary<TKey, TValue>

Появился новый generic тип OrderedDictionary<TKey, TValue>. По сути, это универсальный аналог обычного OrderedDictionary, у которого ключи и значения были представлены типом object.

Новый тип ReadOnlySet<T>

Часто бывают ситуации, когда требуется передать коллекцию только для чтения. Для IList<T> вы использовали ReadOnlyCollection<T>. Когда требовалось передать неизменяемый эквивалент IDictionary<TKey, TValue>, вы использовали ReadOnlyDictionary<TKey, TValue>. Но в случае ISet<T> альтернативы не было. В .NET 9 это исправили, добавив ReadOnlySet<T>.

Новый тип Tensor<T>

Тензоры являются очень важной частью для искусственного интеллекта. Новый тип будет использовать эффективное взаимодействие с такими библиотеками искусственного интеллекта, как ML.NET, TorchSharp и ONNX Runtime.

allows ref struct в библиотеках

В C# 13 появилась возможность указать компилятору и рантайму, что ref struct может использоваться для generic параметра. И в .NET 9 allows ref struct используется во многих местах по всей библиотеке.

[GeneratedRegex] для свойств

Ранее в .NET 7 появился новый способ создания регулярного выражения. Для этого используется генератор исходного кода GeneratedRegex. Он распознаёт использование атрибута [GeneratedRegex] на частичном методе, который возвращает Regex, и автоматически генерирует реализацию метода с логикой работы. Начиная с .NET 9, и благодаря появлению в C# 13 partial свойств, стало возможно использование атрибута [GeneratedRegex] на этих самых свойствах. Например:

[GeneratedRegex(@"\b\w{5}\b")]
private static partial Regex FiveCharWordProperty { get; }

SDK

Terminal Logger включён по умолчанию

Terminal Logger теперь активирован по умолчанию. Это новое средство ведения журнала, которое было представлено в .NET 8. Ранее нужно было включать его с помощью \tl., теперь же Terminal Logger активирован сразу.

Параллельный запуск тестов

Теперь dotnet test способен запускать тесты в разных целевых фреймворках для одного проекта параллельно. При этом всё работает с новым Terminal Logger.

NuGet Audit

В .NET 8 при использовании dotnet restore используемые пакеты проверяются на наличие известных уязвимостей. В .NET 9 по умолчанию изменился режим проверки: теперь на наличие уязвимостей проверяются не только прямые, но и транзитивные зависимости.

Раз уже речь зашла про уязвимые пакеты, то, как и в прошлой статье про .NET 8, напомню: PVS-Studio также умеет искать прямые и транзитивные зависимости, которые содержат известную уязвимость. И, конечно, PVS-Studio может искать потенциальные уязвимости в вашем коде. Вы всегда можете получить триальную лицензию и попробовать анализатор на своей кодовой базе. В этом поможет вот эта страница.

BuildCheck

В .NET 9 появилась новая функция для защиты от ошибок на этапе сборки. Чтобы запустить новый режим, нужно использовать флаг /check. Пока .NET 9 содержит мало проверок, но со временем их количество будет увеличиваться. К тому же можно писать свои собственные правила.

Workload history

Чтобы решить проблему отслеживания изменений workload, в .NET 9 SDK появилась новая команда dotnet workload history. Вы сможете просматривать изменения и откатывать их.

Runtime

Feature switch

Были добавлены два новых атрибута, которые вы можете использовать для переключения между областями функциональности:

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

Динамическая адаптация к размерам приложений (DATAS)

Динамическая адаптация к размерам приложения (DATAS) теперь включена по умолчанию. Эта функция была добавлена в .NET 8. DATAS корректирует размеры куч GC в зависимости от нагрузки приложения.

Улучшение JIT

.NET 9 получил массу улучшений, связанных с JIT. Была улучшена оптимизация циклов, прокачана PGO, улучшено встраивание методов и многое другое. Перечислить все эти улучшения, и тем более объяснить их, будет невероятно сложно. Всем заинтересованным в улучшениях JIT предлагаю ознакомиться с полным списком по ссылке.

Улучшения Register Allocator

В .NET 9 RyuJIT (Just-In-Time компилятор в .NET) использует более быстрый и простой подход для аллокации регистров при компиляции неоптимизированного кода. Подобный подход в некоторых сценариях позволяет сократить время запуска на 10%.

Заключение

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

И повторюсь, в статье я перечислил только самые интересные нововведения, которые были бы полезны большинству разработчиков. Со всеми улучшениями вы можете ознакомиться здесь. Если я упустил какое-то нововведение и для вас оно важно, то пишите об этом комментариях.

Ну вот и всё. Теперь переводим будильник ровно на год и ждём выхода .NET 10. Будем праздновать юбилей, получается :) А пока ждём, расскажите, что вы ожидаете от .NET 10?