Поиск по сайту:

Как будут работать проверки нулевого параметра в C# 11?


Предварительная предварительная версия некоторых функций, которые будут включены в выпуск C# 11 этого года, теперь доступна как часть Visual Studio 2022 Update 1. Наиболее спорным дополнением является встроенная поддержка проверки нулевого значения параметра. При этом используется генерация кода, чтобы исключить ручное сравнение с null.

В этой статье мы рассмотрим текущее состояние функции, критику, направленную против нее, и то, как она может измениться перед финальным релизом. Синтаксис и поведение, описанные здесь, относятся к текущей (март 2022 г.) предварительной версии C# 11 и могут значительно измениться перед запуском.

Что такое проверка нулевого значения параметра?

Сначала уточним, о чем мы говорим. Параметры C# без ссылочных типов, допускающих значение NULL, принимают null в качестве значения независимо от их фактического типа:

private string hello(string name) {
    return "Hello " + name;
}
 
// This works
hello(null);

Такое поведение часто нежелательно. В приведенном выше примере передача null приведет к бессмысленному выводу. Чтобы решить эту проблему, разработчики обычно добавляют свои собственные null-проверки в начало методов:

private string hello(string name) {
 
    if (name is null) {
        throw new ArgumentNullException(nameof(name));
    }
 
    return "Hello " + name;
 
}
 
// ArgumentNullException
hello(null);

Это может создать много стандартного кода, когда метод имеет несколько параметров, не допускающих значение NULL.

Синтаксис проверки нулевого значения параметра в C# 11

C# 11 позволяет сократить приведенный выше пример до следующего кода:

private string hello(string name!!) {
    return "Hello " + name;
}
 
// ArgumentNullException
hello(null);

Специальный синтаксис !! после имени параметра имеет тот же эффект, что и ручной if (... is null)/throw new ArgumentNullException(...) блок. Экземпляр ArgumentNullException будет сгенерирован, если вы передадите null параметру, который использует синтаксис.

Когда несколько параметров помечены как необнуляемые, проверки выполняются в порядке записи параметров. Создаваемое исключение будет ссылаться на первый ненулевой параметр, который получит null в вызове.

Синтаксис можно использовать с большинством типов параметров, в том числе в методах async, итераторах и лямбда-выражениях. Он не работает с параметрами абстрактного метода, параметрами extern и делегата, а также методами интерфейса, которые не являются методом интерфейса по умолчанию (DIM).

Как это работает?

Новый синтаксис основан на генерации кода компилятором. Компилятор создает знакомый код if (... is null)/throw new ArgumentNullException(...) при обработке исходных файлов.

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

Сгенерированный код располагается вверху каждого затронутого метода. Если метод является конструктором, код будет выполняться перед инициализацией полей класса и любыми вызовами конструкторов this и base. Это единственное практическое отличие от созданных вручную выражений проверки на ноль.

Почему это спорно?

Критики предложения обеспокоены синтаксисом (!! плохо передает свое значение и эффект), его присутствием в имени параметра вместо типа и тем, входит ли генерация стандартного кода в компетенцию C#. языковой проект. Также ведутся споры о взаимодействии проверки нулей со ссылочными типами, допускающими значение null.

Давайте разберем некоторые из этих аргументов и их значение.

!! Существует по имени параметра, а не по типу

Написание string param!! кажется неестественным, потому что вы явно наполняете имя параметра дополнительным поведением, а не типом. Однако это полностью соответствует тому, что происходит на самом деле.

Проверка типов — это действие на уровне компилятора; проверка нулевого значения параметра генерирует код времени выполнения, который проверяет значение параметра. Следовательно, синтаксис имеет смысл ориентироваться на параметр, а не на его тип.

Имена параметров не должны всплывать на поверхность деталей реализации

Другая жалоба заключается в том, что param!! передает информацию о реализации метода через его объявление. Синтаксис не влияет на сигнатуру метода, вместо этого раскрывая аспекты его внутреннего устройства. Это не устраивает многих разработчиков.

Одним из распространенных способов решения этой проблемы было бы предоставление поведения проверки нулевого параметра в качестве атрибута. Атрибуты предназначены не для этого — они представляют собой простые метаданные, в то время как нулевые проверки генерируют код времени выполнения. Существует также прецедент поведения !! в других компонентах объявления метода: возьмите async, который показывает, что его цель является асинхронной, и подключает для вас соответствующую модель выполнения. .

Совместимость с нулевыми ссылочными типами

Проверки нулевых параметров и нулевые ссылочные типы (NRT) совместимы друг с другом. Однако вы увидите новые предупреждения компилятора, если вы объедините !! с типом, допускающим значение NULL:

private string hello(string? name!!) {
    // ...
}

В этом примере тип string? явно разрешает null, а name!! отклоняет его во время выполнения. Компилятор обнаруживает это противоречивое состояние и выдает предупреждение:

CS8995 Nullable type 'string?' is null-checked and will throw if null.

Совместимы ли эти два механизма концептуально — это другая проблема. Ссылочные типы, допускающие значение NULL, обеспечивают, чтобы значение не могло быть null во время компиляции. Проверка параметров на нуль вызывает исключение, если значение равно нулю во время выполнения. В идеале было бы необходимо только первое — все методы будут использовать NRT, чтобы указать, могут ли они принимать null, а принудительное выполнение будет полностью выполняться компилятором.

К сожалению, среда C# не идеальна. Ссылочные типы, допускающие значение NULL, — это дополнительная функция, которая не получила повсеместного распространения. Нереально ожидать, что весь существующий код, накопленный за 20 лет существования языка C#, будет поддерживать NRT. Проверка параметров на нуль — это прагматичный способ соединения нового кода, в котором преимущественно используются NRT, со старыми библиотеками, которые могут возвращать null во время выполнения. Они имеют смысл там, где ваши методы могут быть переданы null — поэтому NRT нельзя использовать — кодом, который не принял современный подход.

Ошибочно подходить к param!! как к способу сигнализировать о том, что параметру не следует передавать null — это требование string? обслуживает. Наличие !! известно только компилятору. Он нужен для создания ArgumentNullException от вашего имени.

Генерация кода может быть плохой идеей

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

Разработчики должны понимать, что экземпляры ArgumentNullException могут создаваться везде, где используется !!. Исключение является негибким и не может быть изменено даже в таких ситуациях, как члены экземпляра, где NullReferenceException может быть более подходящим. Это побудило некоторых комментаторов предположить, что проверки параметров на null в их нынешнем виде не должны становиться частью C#.

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

Краткое содержание

Два персонажа вызвали дискуссию, которая все еще продолжается: в нынешнем виде param!! приходит на C# как способ генерировать для вас throw ArgumentNullException(...). Несмотря на его потенциал для сокращения шаблонного кода — более 20 000 явных проверок нуля были удалены из .NET Runtime с использованием синтаксиса — остается ряд непрекращающихся сомнений и опасений.

Мы проанализировали наиболее важные из них выше и увидели, что большинство жалоб необоснованны и основаны на недоразумениях. Возможно, самая большая критика связана с самим синтаксисом, когда !! рассматривается как непрозрачный, трудный для обнаружения и недоступный для новичков. Есть разные предложения заменить его чем-то более очевидным; string param notnull привлекает значительное внимание, поэтому окончательная форма может выглядеть иначе, когда появится C# 11.

Вы можете высказать свое мнение о предложении, участвуя в его обсуждении на GitHub. Если вы хотите попробовать текущую предварительную версию самостоятельно, вам потребуется Visual Studio 17.1 (2022 Update 1) и .NET SDK 6.0.200. Затем вам нужно изменить LangVersion на preview в файле .csproj, чтобы включить поддержку C# 11.




Все права защищены. © Linux-Console.net • 2019-2024