Предварительная версия C# 11: обощённые типы для ML, обязательные члены и многое другое

от автора

Окончательная версия выйдет уже в ноябре, а пока приглашаем под кат, где к старту нашего курса по разработке на C# рассказываем о новой предварительной версии и напоминаем, что у вас есть возможность повлиять на развитие языка.


C# 11 уже близится к завершению. Этот пост посвящён функциям версии Visual Studio 17.3 или тем функциям, которые не освещались в апрельском и февральском выпусках Visual Studio.

Новинки предварительной версии сводятся к трём основным аспектам, на которые мы обращаем особое внимание при разработке C# 11:

  • Улучшенная инициализация объектов: поддержка конструкторов и инициализаторов объектов стала проще при любых правилах для модифицируемых и немодифицируемых членах. Вот элементы новой функциональности языка:
  • Обязательные члены (ключевое слово required).
  • Поля ref.
  • Поддержка универсальной математики: вы можете использовать один написанный вами алгоритм со многими числовыми типами. Это упрощает сбор статистики, машинное обучение и другие прикладные задачи C# и .NET, требующие внушительного объёма вычислений. В том числе предлагаются:
  • Статические члены интерфейса: абстрактные и виртуальные.
  • Ослабление требований к сдвигу вправо.
  • Оператор беззнакового сдвига вправо.
  • Числовой оператор IntPtr.
  • Продуктивность разработчика: новые возможности языка сделают вашу работу продуктивнее. В первую очередь расширена область применения nameof.

Все эти функции описаны ниже со ссылками на разделы документации, где вы можете узнать о них больше. Чтобы протестировать эти возможности, включите в своём проекте функцию предварительного просмотра. Объяснения приводятся в статье «Новые возможности C# 11».

Улучшенная инициализация объектов

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

public class Person {     public string FirstName { get; init; }     public string LastName {get; init; } }

Операторы вызова должны иметь инициализаторы объектов, которые задают свойства FirstName и LastName. До версии 17.3 компилятор не мог заставить операторы вызова устанавливать эти свойства, тогда как конструктор с обязательными параметрами — единственный способ убедиться в том, что пользователь задал свойства FirstName и LastName. Обязательные члены сообщают компилятору и операторам вызова, что эти свойства должны быть заданы. На обязательность указывает ключевое слово required:

public class Person {     public required string FirstName { get; init; }     public required string LastName {get; init; } }

Все операторы вызова должны включать инициализаторы объектов свойств FirstName и LastName, иначе компилятор сообщает, что обязательные члены не заданы, и выдаёт ошибку. Таким образом, разработчик решит эту проблему сразу, а не будет возвращаться к ней на этапе сдачи проекта.

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

public class Person {     public required string FirstName { get; init; }     public required string LastName {get; init; }      [SetsRequiredMembers]     public Person(string firstName, string lastName)     {         this.FirstName = firstName;         this.LastName = lastName;     }      public Person() {} }

Атрибут SetsRequiredMembers требует от конструктора задать все обязательные параметры. Компилятор узнаёт, что Person(string firstName, string lastName) — это параметры, задать которые необходимо. Конструктор без параметров не включает и этот атрибут, поэтому для операторов вызова, использующих этот конструктор, нужно инициализировать все обязательные члены.

В примерах выше изменения касались свойств. Но обязательные члены применимы и к объявлению полей.

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

Поддержка математики с обобщёнными типами

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

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

Компилятор разрешает вызовы методов static, включая операторы, во время компиляции. При этом механизма динамической диспетчеризации, как для методов экземпляра, в этом случае нет. В доках конкретные правила записи этой функции объясняются подробнее.

Другие возможности языка сглаживают некоторые различия числовых типов и облегчают написание обобщённых математических алгоритмов. Оператор сдвига вправо больше не требует, чтобы второй операнд имел тип int. Подойдёт любой целочисленный тип данных! Типы nint и nuint — это синонимы System.IntPtr и System.UIntPtr соответственно. Вместо соответствующих типов можно использовать эти ключевые слова, а новые анализаторы позволяют и даже побуждают делать это. Наконец, оператор беззнакового сдвига вправо (>>>) позволяет избежать приведения типа при выполнении беззнакового сдвига.

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

Продуктивность разработчиков

Теперь оператор nameof можно применять вместе с параметрами методов. То есть вы можете использовать оператор nameof при объявлении атрибутов метода:

[return: NotNullIfNotNull(nameof(url))] string? GetTopLevelDomainFromFullUrl(string? url)

Попробуйте сами

Предлагаем вам скачать предварительные версии Visual Studio 2022 и .NET 7. Вы также можете скачать последнюю предварительную версию .NET 7. После установки вы сможете сами оценить новые функции. Для этого создайте или откройте проект в C# и задайте тегу LangVersion значение Preview.

Предварительная версия Visual Studio приближает нас к полному набору функций C# 11. При разработке новой версии языка мы продолжаем вкладываться в развитие различных аспектов. По вашим отзывам мы внесли корректировки, а теперь — самое время скачать предварительную версию Visual Studio, протестировать новые функции и рассказать нам, что вы думаете о ней. Мы внимательно слушаем вас, пока работаем над окончательными версиями обновлений C# 11 и .NET 7.

Стать востребованным профессионалом в IT с самого начала или прокачаться помогут наши курсы. Скидка 45% по промокоду HABR:

Скидка 45% по промокоду HABR


ссылка на оригинал статьи https://habr.com/ru/company/skillfactory/blog/686880/