Каждой осенью у разработчиков .NET наступает раннее Рождество: последние версии C# и .NET выходят из стадии превью и предоставляются в виде полностью поддерживаемых релизов с долгосрочной (LTS) или стандартной (STS) поддержкой. Этой осенью вышел релиз с долгосрочной поддержкой (LTS), и, вероятно, в течение следующего года многие организации перейдут на него в качестве предпочтительной версии .NET. Хотя есть множество полезных постов, охватывающих весь набор выпускаемых функций и улучшений, цель этой статьи — направить ваше внимание на те из них, которые больше всего впечатлили нашу команду, а именно: Реклама новые возможности языка C#, связанные с методами расширения и синтаксисом полей; улучшения Minimal API и документации OpenAPI в ASP.NET Core 10; новые функции и улучшения для Entity Framework Core; новая модель поддержки релизов без долгосрочной поддержки (non-LTS) Итак, рассмотрим основные моменты. Улучшения в языке C# 14 Хотя в C# 14 представлен ряд изменений, включая расширенную поддержку Span и ReadOnlySpan, новое нулевое условное присваивание (mayBeNull?.Name = "This is only set if mayBeNull is not null"), частичные конструкторы и некоторые другие усовершенствования, хочу выделить несколько изменений, связанных с работой со свойствами. Ключевое слово field В C# автоматические свойства (auto-properties) появились уже давно. Они автоматически создают резервные поля, что приводит к более лаконичному и сфокусированному синтаксису, повышающему производительность разработчика. С годами свойства и автоматические свойства продолжали развиваться и улучшаться, но все еще остаются случаи, когда может потребоваться явное объявление свойства. Например, следующий код раньше требовал объявления поля вручную для проверки: private string _firstName;
public string FirstName
{
   get => _firstName;
   set => _firstName = value ?? throw new InvalidOperationException("First name is required");
} Теперь с ключевым словом field можно полностью отказаться от явного объявления поля и использовать field для ссылки на поле, которое .NET генерирует для нас: public string FirstName
{
   get => field;
   set => field = value ?? throw new InvalidOperationException("First name is required");
} Это минимальное изменение, но мне оно нравится, так как сокращает объем нефункционального кода в файле. Это, в свою очередь, помогает сохранить сфокусированность кода на поведении, а не на структуре или формальностях. Свойства расширений и альтернативный синтаксис методов расширения С появлением LINQ мы получили возможность создавать методы расширения, которые выглядят как новые методы, «присоединенные» к существующим классам, с помощью такого синтаксиса: public static class StringExtensions
{
   public static string DoOurCustomTransform(this string input) 
   {
      return input.ToUpperInvariant().Trim();
   }
} Это позволяло вызывать метод в таких сценариях: string prompt = Console.ReadLine();
string cleaned = prompt.DoOurCustomTransform(); В C# 14 такая функция по-прежнему доступна, но теперь для этого появился альтернативный синтаксис с использованием ключевого слова extension: public static class StringExtensions
{
   extension(string input) 
   {
      public string DoOurCustomTransform()
      {
         return input.ToUpperInvariant().Trim();
      }
   }
} Обратите внимание: параметр перемещён из метода в блок extension, а ключевое слово static больше не требуется. Поскольку я преподаватель в прошлом, считаю, что этот синтаксис будет более интуитивно понятен для новичков. Однако главное преимущество этого синтаксиса — возможность объявлять члены расширения: public static class StringExtensions
{
   extension(string input) 
   {
      public string DoOurCustomTransform()
      {
         return input.ToUpperInvariant().Trim();
      }
      public string CleanedString => input.DoOurCustomTransform();
   }
} В этом блоке добавлено свойство CleanedString, которое использует наше преобразование. Таким образом, можно писать код, вызывающий это свойство (геттер) для любой строки, используя следующий синтаксис: string userInput = Console.ReadLine();
string cleaned = userInput.CleanedString; Это довольно лаконично и удобно, а также расширяет возможности по добавлению новых API к коду и распределению кода по разным файлам, если такая организация для вас целесообразна. Я ожидаю, что свойств расширений будет использоваться меньше, чем методов расширений, но я рад, что такая возможность теперь есть. Кроме того, считаю, что новый опциональный синтаксис более удобен для новичков и полезен для группировки связанных методов расширений и свойств расширений, поэтому, вероятно, я начну постепенно переходить на новый синтаксис при написании кода. Усовершенствования, связанные с Minimal API Изучая полный список изменений в ASP.NET Core 10, можно заметить, что там много всего, связанного с различными аспектами ASP.NET, включая Blazor, аутентификацию, SignalR и другие области. Однако больше всего меня привлекли возможности, связанные с управлением API через Minimal API и OpenAPI. Когда появились Minimal API, они предоставили лаконичный способ определения простых конечных точек в обычном коде C# без необходимости в классах Controller. Эти конечные точки отлично подходили для простых демонстраций и микросервисов, которым не нужно предоставлять широкий спектр различных конечных точек, но им также не хватало некоторых полноценных функций, присущих традиционным контроллерам. В ASP.NET Core 10 предусмотрен ряд улучшений для конечных точек Minimal API, включая: улучшенную обработку пустых строк в телах запросов; поддержку атрибутов валидации и IValidatableObject; предоставление детализации проблем с помощью IProblemDetailsService; поддержку событий, отправляемых сервером. Также мы видим новые улучшения в виде возможности поддержки OpenAPI 3.1 и значительное количество новых способов предоставления документации API через конечные точки Minimal API, включая: более точную документацию типов с использованием OpenAPI 3.1; свойство Description для аннотаций ProducesResponseType; поддержку XML-документации для Minimal API со ссылкой на именованный метод для обработки; поддержку внедрения зависимости IOpenApiDocumentProvider для более сложных сценариев; различные другие улучшения документации, связанные с AsParameters, сценариями JSON Patch и многое другое Хотя ни одно из этих улучшений не выделяется само по себе, вместе они свидетельствуют о достижении более профессиональных результатов при использовании Minimal API в рабочих сценариях и о лучшей поддержке документации OpenAPI. Функции Entity Framework Core 10 В EF Core 10 появилось много нового, как можно увидеть из обзора полного списка изменений, но выделю несколько ключевых моментов — работу с эмбеддингами, объединениями и сложными типами, которые расширяют возможности EF для обработки более профессиональных сценариев. Во-первых, EF добавил поддержку эмбеддингов для Azure SQL и SQL Server посредством объявления столбца SqlVector<float>. Это позволяет использовать генератор эмбеддингов для вычисления векторных представлений текста элемента и хранения в этом столбце. Затем можно использовать функцию EF.Functions.VectorDistance для вычисления расстояния между сохранёнными эмбеддингами и поисковым запросом. Эта поддержка векторов становится всё более актуальной в мире с искусственным интеллектом, где эмбеддинги критически важны для обеспечения возможностей RAG, таких как те, что можно увидеть в чат-приложениях, использующих эту технологию. Во-вторых, EF теперь поддерживает столбцы со сложными свойствами из JSON-данных. Это позволяет использовать строго типизированные определения классов C# для представления данных, которые хранятся в виде JSON в строках базы данных, не беспокоясь о сложностях сериализации и десериализации. Хотя я стараюсь избегать хранения JSON в базах данных, бывают случаи, когда это неизбежно или целесообразно для конкретного сценария. В таких случаях работать со сложными свойствами из JSON-данных очень удобно. Кроме того, в EF представлен ряд других интересных функций, таких как фильтры именованных запросов, которые можно определять и при необходимости отключать. Это помогает сократить код, если вы часто используете одни и те же проверки (например, фильтрацию удаленных записей). Очень рад был увидеть улучшения оптимизации запросов к SQL, которые увеличивают вероятность использования плана кэшированного запроса при применении оператора IN, так как я часто на него полагаюсь. Наконец, я очень впечатлен добавлением анализатора кода, который может помечать случаи, когда выполнение необработанного SQL-запроса делает возможным SQL-инъекции, поскольку эти атаки остаются распространенной уязвимостью для команд даже в конце 2025 года. Изменения в стандартном сроке поддержке (STS) Одним из самых значительных изменений в этом году в контексте LTS-релиза является изменение не самого релиза, а того, как долго будут поддерживаться STS-релизы. .NET выпускает релизы с долгосрочной поддержкой (LTS) через год, а в промежуточные годы выходят релизы со стандартным сроком поддержки (STS). Это позволяет .NET продолжать поставлять новые функции и улучшения, но при этом дает организациям стабильность и долгосрочную поддержку, если они не могут часто обновляться. Однако эти STS-релизы в основном использовались в непроизводственных сценариях, а их полные функции перенимались организациями в составе следующего LTS-релиза. Это происходило потому, что срок поддержки STS-релизов истекал раньше, чем у предыдущего LTS-релиза. Это означало, что у организаций, обновляющихся с LTS до следующего STS-релиза, дата окончания поддержки их приложения сдвигалась вперед при переходе на STS-релизы. Как следствие, большинство организаций оставались на LTS-релизах и использовали STS-релизы только в том случае, если им было критически важно получить что-то из нововведений. С новым изменением STS-релизы теперь поддерживаются в течение 24 месяцев вместо 18. Это означает, что по сути для организации теперь нет никаких негативных последствий при переходе на STS-релиз, если она этого захочет, или при начале новых проектов с использованием этого STS-релиза вместо предпочтительного LTS-релиза. Иллюстрация Microsoft нового жизненного цикла поддержки Это изменение, будем надеяться, облегчит организациям внедрение STS-релизов и обеспечит одинаковую значимость LTS-релизов и будущих STS-релизов. Заключительные мысли Я лишь поверхностно коснулся того, что готовят C# 14 и .NET 10, но надеюсь, вы уловили общую тенденцию: мы видим не несколько громких нововведений, а платформу, которая продолжает оставаться актуальной и ежегодно улучшаться за счет новых удобств, поддержки отраслевых трендов, повышения производительности и последовательного совершенствования существующего функционала. Я с энтузиазмом работаю с этими инструментами как в своих личных проектах, так и с клиентами, и я рад, что .NET продолжает идти по пути инноваций и развития. Читайте также: Зачем использовать HttpClientFactory вместо HttpClient в .NET Встроенная поддержка контейнеров для .NET 7  —  контейнеризация приложений .NET без Dockerfile C# —  создаем клиент-серверный чат на TCP Читайте нас в Telegram, VK и Дзен Перевод статьи Matt Eland: Our Favorite New Features in .NET 10 and C# 14
==============
Вышла новая версия .NET, включающая C# 14 и .NET 10, с множеством улучшений. Особенно выделяются новые возможности языка C#, такие как расширения и синтаксис полей, улучшения Minimal API и документации OpenAPI в ASP.NET Core 10, а также новые функции и улучшения для Entity Framework Core. Также важны улучшения в поддержке релизов без долгосрочной поддержки (non-LTS) и изменения в стандартном сроке поддержки (STS), где теперь STS-релизы поддерживаются в течение 24 месяцев. Общая тенденция - это постоянное улучшение платформы, добавление новых удобств, поддержка отраслевых трендов, повышение производительности и совершенствование существующего функционала.