Поделиться через


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

C# 14 включает следующие новые функции. Эти функции можно попробовать с помощью последней версии Visual Studio 2022 или пакета SDK для .NET 10:

C# 14 поддерживается в .NET 10. For more information, see C# language versioning.

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

Новые функции добавляются на страницу "Новые возможности В C#", когда они доступны в общедоступных предварительных версиях. The working set section of the roslyn feature status page tracks when upcoming features are merged into the main branch. Эта статья была обновлена для .NET 10 (предварительная версия 1).

Критические изменения, внесенные в C# 14, можно найти в нашей статье о критических изменениях.

Примечание.

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

Члены расширения

C# 14 добавляет новый синтаксис для определения элементов расширения. Новый синтаксис позволяет объявлять свойства расширения в дополнение к методам расширения. Можно также объявить члены расширения, которые расширяют сам тип, а не экземпляры этого типа. Другими словами, эти новые члены расширения могут отображаться как статические элементы расширенного типа. В следующем примере кода показан пример различных типов элементов расширения, которые можно объявить:

public static class Enumerable
{
    // Extension block
    extension<TSource>(IEnumerable<TSource> source) // extension members for IEnumerable<TSource>
    {
        // Extension property:
        public bool IsEmpty => source.Any() == false;
        // Extension indexer:
        public TSource this[int index] => source.Skip(index).First();

        // Extension method:
        public IEnumerable<TSource> Where(Func<TSource, bool> predicate) { ... }
    }

    // extension block, with a receiver type only
    extension<TSource>(IEnumerable<TSource>) // static extension members for IEnumerable<Source>
    {
        // static extension method:
        public static IEnumerable<TSource> Combine(IEnumerable<TSource> first, IEnumerable<TSource> second) { ... }

        // static extension property:
        public static IEnumerable<TSource> Identity => yield return default;
    }
}

Элементы в первом блоке расширения вызываются так, как будто они являются членами экземпляра IEnumerable<TSource>, например sequence.IsEmpty. Элементы во втором блоке расширения вызываются так, как будто они являются статическими элементами IEnumerable<TSource>, например IEnumerable<int>.Identity.

Дополнительные сведения см. в статье о членах расширений в руководстве по программированию, справочной статье extensionпо языку ключевого слова и спецификации компонентов для новых элементов расширения.

Ключевое слово field

Токен field позволяет вам написать тело доступа к свойству, не объявляя явное поле для хранения данных. Маркер field заменяется на поле синтезированной резервной копии компилятора.

Например, ранее, если вы хотели убедиться, что свойство string не может быть установлено в null, вам нужно было объявить резервное поле и реализовать оба аксессора.

private string _msg;
public string Message
{
    get => _msg;
    set => _msg = value ?? throw new ArgumentNullException(nameof(value));
}

Теперь вы можете упростить код следующим образом:

public string Message
{
    get;
    set => field = value ?? throw new ArgumentNullException(nameof(value));
}

You can declare a body for one or both accessors for a field backed property.

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

Если вы попробуете использовать эту функцию и у вас будут отзывы, оставьте комментарий о вопросе относительно функции в репозитории csharplang.

Контекстное ключевое слово field представлено в C# 13 в качестве предварительной функции.

Неявные преобразования диапазона

C# 14 предоставляет первоклассную поддержку для System.Span<T> и System.ReadOnlySpan<T> в языке. Эта поддержка включает новые неявные преобразования, позволяющие более естественное программирование с этими типами.

Span<T> и ReadOnlySpan<T> используются различными ключевыми способами в C# и среде выполнения. Их введение повышает производительность без риска безопасности. C# 14 распознает связь и поддерживает некоторые преобразования между ReadOnlySpan<T>, Span<T>и T[]. Типы span могут выступать в качестве получателей методов расширения, комбинироваться с другими преобразованиями и помогать в ситуациях вывода универсальных типов.

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

Несвязанные обобщенные типы и nameof

Начиная с C# 14 аргумент nameof может быть несвязанным универсальным типом. Например, nameof(List<>) принимает значение List. В более ранних версиях C# для возврата List<int> имени можно использовать только закрытые универсальные типы, напримерList.

Простые лямбда-параметры с модификаторами

Модификаторы параметров, например scoped, , ref, inoutили ref readonly лямбда-выражения, можно добавить без указания типа параметра:

delegate bool TryParse<T>(string text, out T result);
// ...
TryParse<int> parse1 = (text, out result) => Int32.TryParse(text, out result);

Ранее добавление модификаторов было разрешено только в том случае, если объявления параметров включали типы параметров. The preceding declaration would require types on all parameters:

TryParse<int> parse2 = (string text, out int result) => Int32.TryParse(text, out result);

Модификатор params по-прежнему требует явно типизированного списка параметров.

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

More partial members

You can now declare instance constructors and events as partial members.

Частичные конструкторы и частичные события должны включать ровно одно определение объявления и одно реализующее объявление.

Только реализующее объявление частичного конструктора может включать инициализатор конструктора: this() или base(). Только одно объявление частичного типа может включать синтаксис основного конструктора.

Объявление реализации частичного события должно включать аксессоры add и remove. The defining declaration declares a field-like event.

Условное присваивание null

Операторы доступа к членам с нулевым условием, ?. и ``?[]`, теперь могут использоваться на левой стороне присваивания или составного присваивания.

До C# 14 необходимо было проверять переменную на null, прежде чем присваивать значение свойству.

if (customer is not null)
{
    customer.Order = GetCurrentOrder();
}

Вы можете упростить предыдущий код, используя оператор ?..

customer?.Order = GetCurrentOrder();

Правая сторона оператора вычисляется только в том случае, если левая сторона = не имеет значения NULL. Если customer является null, код не вызывает GetCurrentOrder.

В дополнение к присваиванию, вы можете использовать условные операторы доступа к членам с операторами присваивания с составными выражениями (+=, -=, и другие). Однако инкремент и декремент, ++ и --, не разрешены.

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

См. также