Что нового будет в C# 9? Результаты исследования Proposals на GitHub
Предупреждён — значит вооружён. Обсуждаем предлагаемые нововведения, которые могут коснуться разработчиков в девятой версии С#.
Следующим релизом C# станет С# 9. В плане развития языка уже описано 39 предложений (proposals) для девятой версии. Но какие предложения будут внедрены и в какой версии? Только команда разработчиков .Net может ответить на этот вопрос. Наиболее важные функции, запланированные в C# 9, это новый тип – записи (records), дизъюнктные объединения (discriminated unions), улучшение сопоставления с образцом (pattern matching), дополнительная целевая типизация существующих конструкций, таких как тернарные выражения и выражения объединения с null
. Бассам Алугили в публикации Глубокое погружение в C # 9 (англ.) описал ключевые изменения, которые могут появиться в новой версии языка. Мы представляем незначительно сокращённый перевод статьи.
Указанные особенности ещё не находятся на заключительной стадии. И окончательный синтаксис может отличаться от описанного в proposals.
Записи
Записи (records) представляют собой новую упрощенную форму объявления классов C# и структурных типов. Описание этого нового типа дано на GitHub. Актуальная версия предложения изложена здесь.
Записи номинально типизированы и могут иметь методы, свойства, операторы и т. д., позволяют проводить структурное сравнение. По умолчанию свойства записи доступны только для чтения. Записи могут быть Value Type
или Reference Type
.
Запись может быть определена следующим образом:
В случае неизменного типа предлагается использовать новый модификатор initonly
, который можно применять к свойствам и полям:
Создание объекта записи:
Использование записей с with-выражениями
Во вводной части заявки на внедрение записей в качестве нового элемента языка предлагаются with
-выражения. С помощью with
можно сразу изменять копию объекта записи:
Созданная новая точка newPoint3D
аналогична существующей point3D
, но значение X изменено на 42.
Равенство
Записи сравниваются по структуре, а не по ссылке:
Дизъюнктное объединение
Термин дизъюнктное объединение (discriminated union, disjoint union) заимствован из математики. Например, есть связанные множестваA0 = {(5,0), (6,1)}
и A1 = {(7,2)}
. Дизъюнктное объединение заключается в объединении непересекающихся «копий» множеств:
A0 ⊔ A1 = {(5,0), (6,1), (7,2)}
Предлагаемая функциональность дизъюнктного объединения в C#9 аналогична F# и позволяет определять типы, которые могут содержать любое количество различных типов данных, объединения полезны для различных неоднородных данных и создания простых иерархических структур.
Пример дизъюнктного объединения в F#:
Возьмём для дизъюнктного объединения в С# 9 пару сущностей:
Во втором случае мы хотим тип, который отражает все возможные целые числа и все возможные булевы значения:
В нашем случае новый тип ByteOrBool – это «сумма» байтового и логического типов. Как и в F#, суммарный тип называется discriminated union
(дизъюнктное объединение).
Создание экземпляра объединения:
Использование дизъюнктных объединений
Приведенные ниже примеры демонстративные, только для лучшего понимания предлагаемых новшеств.
1. Обработка исключений, как в Java:
2. Ограничение типа:
Универсальный класс может принадлежать одному из типов T1
, T2
или T3
.
3. Гетерогенные коллекции:
4. Комбинация переменных/значений/выражений разных типов через операторы ? :
, ??
или выражение switch
:
Тип результата здесь будет string | int
.
5. Если несколько перегрузок какого-либо метода имеют одинаковые реализации, их можно объединить. Например, следующий набор
может быть заменен на единственную строку:
6. Можно использовать подход для возвращаемых типов:
Оператор объединения с null (??)
Речь идет о разрешении неявного преобразования для выражений, в которых происходит объединение с null
. Вот пример в C# 8:
В C# 9 тот же код будет выглядеть так:
Выражение new
Рассмотрим пример из официального предложения.
Приведённый код может быть упрощен до следующего
Но вам всё равно нужно повторно указать тип после инициализации поля/свойства. Самое близкое, что можно получить, это что-то вроде:
Для полноты картины можно предложить также сделать new[]
выражением с типом целевого объекта.
Атрибут вызываемого выражения
Идея состоит в том, чтобы позволить вызывающему объекту «структурировать» выражения, переданные на место вызова. Конструктор атрибута примет строковый аргумент, определяющий имя аргумента для строкового преобразования.
Упрощённая default-деконструкция кортежа:
В C# 7 сопоставляем каждой переменной default
:
В C# 9 проще:
Свободный порядок модификаторов ref и partial
При объявлении класса можно указывать partial
перед ref
:
Проверка на null
Задача – упростить стандартную null проверку параметров, используя небольшую аннотацию параметров. Эта функция относится к улучшению качества кода. Подробнее смотрите в заметках об обсуждении.
Пустые параметры для лямбда-выражений
Идея состоит в том, чтобы разрешить при вводе лямбда-выражений множественные объявления параметров с именем _
. В этом случае параметры являются «сброшенными» (discard) и не могут использоваться внутри лямбды:
Атрибуты локальных функций
Идея состоит в том, чтобы позволить атрибутам быть частью объявления локальной функции.
Пример:
Еще один пример использования – с EnumeratorCancellation
для параметра CancellationToken
локальной функции, реализующей асинхронный итератор, что часто встречается при реализации операторов запросов.
Native Int
Предлагается ввести набор нативных типов (nint
, nuint
). Планируется, что дизайн новых типов данных позволит одному исходному файлу C# использовать 32- или 64-разрядные хранилища в зависимости от типа платформы хоста и настроек компиляции.
Тип определяется ОС:
Указатели на функции
Термин «указатель на функцию» многим известен из С/С++. В переменной хранится адрес функции, которая впоследствии может быть вызвана через указатель этой функции. Указатели на функции можно вызывать и передавать им аргументы, как при обычном вызове функции. Подробнее читайте в описании предложения.
Указатель на функцию C# позволяет объявлять указатели на функции с использованием синтаксиса func*
. Это похоже на синтаксис, используемый при объявлении делегатов:
Заключение
Итак, вы прочитали о кандидатах в C# 9. Также вы можете посмотреть список рабочих изменений C# NEXT. Только если функции-кандидаты находятся в ветви master
, они будут выпущены в следующей версии. Многое ещё обсуждается, предложенные функции и синтаксис/семантика могут быть изменены.