.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

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

Новый тип ReadOnlySet

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

Новый тип Tensor

Тензоры являются очень важной частью для искусственного интеллекта. Новый тип будет использовать эффективное взаимодействие с такими библиотеками искусственного интеллекта, как 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?

Если хотите поделиться этой статьей с англоязычной аудиторией, то прошу использовать ссылку на перевод: Artem Rovenskii. What's new in .NET 9?.

Комментарии (22)


  1. rukhi7
    13.11.2024 09:18

    .NET 9 вышел в релиз, и значит, можно начинать переносить свои проекты на новую версию.

    А что микрософт отказался от обратной совместимости? Он может, как раз, за счет мастерства по обратной совместимости и существует до сих пор.


    1. vabka
      13.11.2024 09:18

      Тут у нас акцент на "вышел в релиз". Ранее не стоило переносить, тк был не в релизе, а значит могли происходить ломающие изменения и баги.

      А кроме этого:

      1. Переход на новую версию - это не только бамп версии, но ещё и:

        1. Проверка, что ты не попал на breaking changes

          Между мажорными версиями у Microsoft всегда были какие-то breaking changes.
          Тот же новый логгер вполне может сломать твои CI-инструменты, если они парсили выхлоп от sdk.
          Полная обратная совместимость была только в рамках одной мажорной версии.

        2. Начало использования новых фичей

      2. Никто не отменяет багов в новой версии, которые проскочили через много кругов тестирования => при переходе на новую мажорную версию стоит провести хоть какой-то минимальный регресс


  1. Ilay_Developer
    13.11.2024 09:18

    выжимают последние соки из .NET. Похоже конкуренты сильно достали со своими зелёными потоками, нативными компиляциями и т. д.


  1. Mingun
    13.11.2024 09:18

    Появился новый generic тип OrderedDictionary.

    Да неужто?! Сколько лет им потребовалось для этого? Кстати, уж здесь-то Keys и Values реализуют уже наконец IList<T> или по-прежнему дело лишь ICollection<T> ограничивается?


    1. goremukin
      13.11.2024 09:18

      реализуют уже наконец IList<T> или по-прежнему дело лишь ICollection<T> ограничивается?

      Какой смысл неупорядоченной коллекции было реализовывать интерфейс с индексацией, который предполагает порядок?

      Более того, IList предоставляет множество изменяющих методов. Согласитесь, выглядит бессмысленно:

      dictionary.Values.Add()


      1. Mingun
        13.11.2024 09:18

        Какой смысл неупорядоченной коллекции

        В смысле, неупорядоченной? Ordered в названии коллекции просто так стоит, что ли?

        IList предоставляет множество изменяющих методов

        Как и ICollection, но вас же это не смущает.


        1. goremukin
          13.11.2024 09:18

          Вы написали таким образом, как будто давно нужно было сделать IList. На это указывают слова "уже наконец" и "или по-прежнему дело лишь ограничивается".
          А я вам объясняю почему это было абсолютно бессмысленно реализовывать.

          Согласен, ICollection тоже плохой вариант. Но всё-таки предоставляет меньше возможностей редактирования.


          1. Mingun
            13.11.2024 09:18

            На это указывают слова "уже наконец" и "или по-прежнему дело лишь ограничивается".

            Всё правильно. Коллекция OrderedDictionary (не типизированная) существует в .Net аж со 2-й его версии. Но свойства Keys и Values почему-то являются лишь ICollection вместо логичного в этом случае IList. C# вполне спокойно позволяет затенить в интерфейсе-наследнике метод интерфейса-родителя посредством ключевого слова new при объявлении свойства. Так же есть возможность одновременно реализовать два интерфеса с пересекающимися методами/свойствами посредством явной реализации интерфейса. Что мешало это сделать, мне решительно непонятно.

            Я надеялся, что с внедрением нового класса была всё-таки проведена работа над ошибками и этот косяк в дизайне был поправлен хотя бы в нём. Но воз так и остался на месте.


            1. goremukin
              13.11.2024 09:18

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

              Да, в новом можно было бы IReadOnlyList реализовать в крайнем случае.


              1. withkittens
                13.11.2024 09:18

                Так ведь реализовали же? Вот Keys, вот Values.


                1. goremukin
                  13.11.2024 09:18

                  Хоть кто-то проверил)


                1. Mingun
                  13.11.2024 09:18

                  Опа! Кажется, я не в то свойство посмотрел — на явную реализацию интерфейса IDictionary<TKey, TValue>. Что же, тогда претензия снимается.


  1. mirasayon
    13.11.2024 09:18

    Опытные ребята на дотнете, можете пожалуйста дать совет на каком IDE (или на редакторе кода) разрабатывать на Линуксе?


    1. stepagrus
      13.11.2024 09:18

      JetBrains Rider


    1. Blizzaga
      13.11.2024 09:18

      Rider. Он теперь бесплатный для некоммерческого использования.


    1. goremukin
      13.11.2024 09:18

      Rider. Но бесплатная версия не подходит для коммерческого использования.

      Как опцию можете попробовать VS Code + C# Dev Kit. У dev kit лицензия как у Visual Studio Community. Позволяет коммерческое использования если небольшая команда или доход компании небольшой. Лично я не пробовал, но вижу некоторые блогеры уже используют.


      1. mirasayon
        13.11.2024 09:18

        Но бесплатная версия не подходит для коммерческого использования

        Что будет если юзать для коммерции?


        1. goremukin
          13.11.2024 09:18

          Совесть грызть будет


  1. Kononvaler
    13.11.2024 09:18

    С каждым релизом еще более повышается производительность. Лондонскую биржу скоро опять можно будет пробовать переводить нанет ?


    1. KReal
      13.11.2024 09:18

      Да.


    1. Kononvaler
      13.11.2024 09:18

      А что за минусы? апологетам обидно за прошлый громкий провал?


  1. Gromilo
    13.11.2024 09:18

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