Окончательная версия выйдет уже в ноябре, а пока приглашаем под кат, где к старту нашего курса по разработке на 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
. На данный момент описания функций и изменений в новой версии — лучшая доступная документация по этой теме. Мы обнаружили несколько ситуаций, где для безопасного применения новой фичи потребовались обновления языка. Эти обновления появятся в более поздней предварительной версии, а документация по ней будет отражать функциональность окончательной версии.
Поддержка математики с обобщёнными типами
Добавлен ряд функций для поддержки математики с обобщёнными типами. Новая функциональность, вероятно, пригодятся вам только в сложных ситуациях с написанием алгоритмов, которые должны работать с разными типами чисел. Но, даже если вы не пишете таких алгоритмов, то сможете извлечь косвенную выгоду, ведь среда выполнения использует функциональность из списка ниже:
- Статические члены интерфейса: абстрактные и виртуальные.
- Ослабление требований к сдвигу вправо.
- Оператор беззнакового сдвига вправо.
- Числовой оператор IntPtr.
Появление в интерфейсе статических абстрактных и виртуальных членов коснётся большей части расчётов с обобщёнными типами. Они позволяют объявлять операторы и другие статические методы прямо из интерфейса. Классы, реализующие интерфейс, должны поддерживать 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. После установки вы сможете сами оценить новые функции. Для этого создайте или откройте проект в C# и задайте тегу LangVersion
значение Preview
.
Предварительная версия Visual Studio приближает нас к полному набору функций C# 11. При разработке новой версии языка мы продолжаем вкладываться в развитие различных аспектов. По вашим отзывам мы внесли корректировки, а теперь — самое время скачать предварительную версию Visual Studio, протестировать новые функции и рассказать нам, что вы думаете о ней. Мы внимательно слушаем вас, пока работаем над окончательными версиями обновлений C# 11 и .NET 7.
Стать востребованным профессионалом в IT с самого начала или прокачаться помогут наши курсы. Скидка 45% по промокоду HABR: