Новые возможности C# 11

В C# 11 были добавлены следующие функции:

C# 11 поддерживается в .NET 7. Дополнительные сведения см. в статье Управление версиями языка C#.

Последнюю версию пакета SDK для .NET 7 можно скачать на странице загрузок .NET. Вы также можете скачать Visual Studio 2022, который включает пакет SDK для .NET 7.

Примечание

Мы заинтересованы в ваших отзывах об этих функциях. Если вы обнаружите проблемы с любой из этих новых функций, создайте новую проблему в репозитории dotnet/roslyn .

Универсальные атрибуты

Можно объявить универсальный класс, базовым классом которого является System.Attribute. Эта функция предоставляет более удобный синтаксис для атрибутов, для которых требуется System.Type параметр . Ранее вам пришлось бы создать атрибут, который принимает Type качестве параметра конструктора:

// Before C# 11:
public class TypeAttribute : Attribute
{
   public TypeAttribute(Type t) => ParamType = t;

   public Type ParamType { get; }
}

А для применения атрибута следовало бы использовать оператор typeof:

[TypeAttribute(typeof(string))]
public string Method() => default;

С помощью этой новой функции можно создать универсальный атрибут:

// C# 11 feature:
public class GenericAttribute<T> : Attribute { }

Затем укажите параметр типа для использования атрибута:

[GenericAttribute<string>()]
public string Method() => default;

При применении атрибута необходимо указать всех параметры типа. То есть универсальный тип должен быть создан полностью. В приведенном выше примере пустые скобки (( и )) можно опустить, так как атрибут не имеет аргументов.

public class GenericType<T>
{
   [GenericAttribute<T>()] // Not allowed! generic attributes must be fully constructed types.
   public string Method() => default;
}

Аргументы типа должны соответствовать тем же ограничениям, что и оператор typeof. Типы, которым требуются аннотации метаданных, запрещены. Например, следующие типы не допускаются в качестве параметра типа:

  • dynamic
  • string? (или любой ссылочный тип, допускающий значение NULL)
  • (int X, int Y) (или любые другие типы кортежей, использующие синтаксис кортежей C#).

Эти типы не представлены непосредственно в метаданных. Они содержат заметки, описывающие тип. Во всех случаях можно использовать базовый тип:

  • object для dynamic.
  • string вместо string?.
  • ValueTuple<int, int> вместо (int X, int Y).

Поддержка универсальной математики

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

  • static virtual члены в интерфейсах
  • проверенные определяемые пользователем операторы
  • операторы незащищенного сдвига
  • оператор unsigned right-shift

В интерфейсы можно добавлять static abstract элементы или static virtual , чтобы определить интерфейсы, которые включают перегруженные операторы, другие статические члены и статические свойства. Основным сценарием для этой функции является использование математических операторов в универсальных типах. Например, интерфейс можно реализовать System.IAdditionOperators<TSelf, TOther, TResult> в типе , который реализует operator +. Другие интерфейсы определяют другие математические операции или четко заданные значения. Вы можете узнать о новом синтаксисе в статье об интерфейсах. Интерфейсы, включающие static virtual методы, обычно являются универсальными интерфейсами. Кроме того, большинство из них объявит ограничение, которое параметр типа реализует объявленный интерфейс.

Вы можете узнать больше и опробовать функцию в учебнике Статические абстрактные члены интерфейса или в записи блога об универсальных математических операциях в предварительных версиях функций .NET 6.

Универсальная математика создала другие требования к языку.

  • оператор сдвига вправо без знака. Перед C# 11 для принудительного сдвига без знака вправо необходимо привести любой целочисленный тип со знаком к типу без знака, выполнить сдвига, а затем вернуть результат к подписанному типу. Начиная с C# 11, можно использовать >>>оператор сдвига без знака.
  • Требования к оператору сдвига с ослабленным смещением. C# 11 устраняет требование о том, что второй операнд должен быть int или неявно преобразован в int. Это изменение позволяет использовать в этих расположениях типы, реализующие универсальные математические интерфейсы.
  • проверенные и неконтролированные определяемые пользователем операторы. Теперь разработчики могут определять checked операторы и unchecked арифметические операторы. Компилятор создает вызовы правильного варианта на основе текущего контекста. Дополнительные сведения об checked операторах см. в статье об арифметических операторах.

Числовые IntPtr и UIntPtr

Теперь nint и nuint типы псевдонимов System.IntPtr и System.UIntPtrсоответственно.

Новые строки в интерполяциях строк

Текст между символами { и } для интерполяции строки теперь может находиться на нескольких строках. Текст между метками { и } анализируется как код C#. Разрешен любой допустимый код C#, включая новые строки. Эта функция упрощает чтение интерполяций строк, использующих более длинные выражения C#, такие как выражения switch для сопоставления шаблонов или запросы LINQ.

Дополнительные сведения о функции новых строк см. в статье об интерполяции строк в справочнике по языку.

Шаблоны списков

Шаблоны списков расширяют сопоставление шаблонов для сопоставления последовательностей элементов в списке или массиве. Например, sequence is [1, 2, 3] имеет значение true, если sequence является массивом или списком трех целых чисел (1, 2 и 3). Элементы можно сопоставлять с помощью любого шаблона, включая константу, тип, свойство и реляционные шаблоны. Шаблон отмены (_) сопоставляется с любым отдельным элементом, а новый шаблон диапазона (..) сопоставляется с любой последовательностью элементов (от нуля и больше).

Дополнительные сведения о шаблонах списков см. в статье о сопоставлении шаблонов справочника по языку.

Улучшенное преобразование групп методов для делегирования

Стандарт C# по преобразованиям групп методов теперь включает следующее:

  • Преобразованию разрешено (но не обязательно) использовать существующий экземпляр делегата, который уже содержит эти ссылки.

Предыдущие версии стандарта запрещали компилятору использовать повторно объект-делегат, созданный для преобразования группы методов. Компилятор C# 11 кэширует объект-делегат, созданный из преобразования группы методов и повторно использует такой отдельный объект-делегат. Эта функция была впервые доступна в Visual Studio 2022 версии 17.2 в качестве предварительной версии и в предварительной версии 2 .NET 7.

Необработанные строковые литералы

Необработанные строковые литералы — это новый формат для строковых литералов. Необработанные строковые литералы могут содержать любой текст, в том числе пробелы, переходы строк, кавычки и другие специальные символы, без необходимости указывать escape-последовательности. Необработанный строковый литерал начинается с по меньшей мере трех символов двойных кавычек ("""). Заканчивается он таким же числом символов двойных кавычек. Как правило, необработанный строковый литерал использует три двойных кавычки на одной строке для указания начала строки и три двойных кавычки на отдельной строке для ее завершения. Новые линии после открывающей кавычки и перед закрывающей кавычками не включаются в окончательное содержимое:

string longMessage = """
    This is a long message.
    It has several lines.
        Some are indented
                more than others.
    Some should start at the first column.
    Some have "quoted text" in them.
    """;

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

var location = $$"""
   You are at {{{Longitude}}, {{Latitude}}}
   """;

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

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

Автоструктура по умолчанию

Компилятор C# 11 гарантирует, что все поля struct типа будут инициализированы значением по умолчанию в рамках выполнения конструктора. Это изменение означает, что любое поле или автоматическое свойство, не инициализированное конструктором, автоматически инициализируется компилятором. Структуры, в которых конструктор не назначает все поля, теперь компилируются, а всем полям, не инициализированным явно, присваивается значение по умолчанию. Дополнительные сведения о том, как это изменение влияет на инициализацию структуры, см. в статье о структуре.

Соответствие Span<char> шаблону или ReadOnlySpan<char> константе string

Вы смогли проверить string наличие определенного постоянного значения с помощью сопоставления шаблонов для нескольких выпусков. Теперь можно использовать ту же логику сопоставления шаблонов с переменными или Span<char>ReadOnlySpan<char>.

Расширенное имя область

Имена параметров типа и имена параметров теперь находятся в область при использовании в nameof выражении в объявлении атрибута для этого метода. Эта функция означает, что с помощью nameof оператора можно указать имя параметра метода в атрибуте в объявлении метода или параметра. Эта функция чаще всего полезна для добавления атрибутов для анализа, допускающих значение NULL.

Строковые литералы UTF-8

Можно указать суффикс u8 в строковом литерале, чтобы указать кодировку символов UTF-8. Если приложению требуются строки UTF-8, для констант http-строк или аналогичных текстовых протоколов можно использовать эту функцию, чтобы упростить создание строк UTF-8.

Дополнительные сведения о строковых литералах UTF-8 см. в разделе строковых литерала статьи о встроенных ссылочных типах.

Обязательные члены

Модификатор можно добавить к свойствам и полям, чтобы применить конструкторы и вызывающие объекты для инициализации required этих значений. Объект System.Diagnostics.CodeAnalysis.SetsRequiredMembersAttribute можно добавить в конструкторы, чтобы сообщить компилятору о том, что конструктор инициализирует все необходимые члены.

Дополнительные сведения о необходимых элементах см. в разделе только для инициализации статьи о свойствах.

ref поля и ref scoped переменные

Поля можно объявлять ref внутри ref struct. Это поддерживает типы, например System.Span<T> без специальных атрибутов или скрытые внутренние типы.

Модификатор можно добавить в scoped любое ref объявление. Это ограничивает область, куда может экранироваться ссылка.

Локальные типы файлов

Начиная с C# 11, модификатор file доступа можно использовать для создания типа, видимость которого ограничена исходным файлом, в котором он объявлен. Эта функция помогает авторам генераторов источников избежать конфликтов имен. Дополнительные сведения об этой функции см. в статье о типах в области файла в справочнике по языку.

См. также раздел