Вопрос или проблема
Я большой поклонник шаблона try в C#, особенно из-за возможности использовать статический анализ для добавления подсказок о возможности null с помощью атрибутов [MaybeNullWhen]
и/или [NotNullWhen]
.
Что я не понимаю, так это разницу между ними. Разве они не одинаковы с учетом противоположного условия? Например:
bool | MaybeNullWhen(false) | NotNullWhen(true) |
---|---|---|
true | не null | не null |
false | может быть null | может быть null |
Существует ли семантическая разница, которую я упускаю?
Здесь есть немного истории.
nullable reference types и эти два атрибута были введены в C# 8. Однако синтаксис T?
(описывающий обобщенный тип как “поддерживающий значение по умолчанию”) был введен только в C# 9.
Когда были введены NRT, вы не могли написать это:
public bool TryGetValue(TKey key, [NotNullWhen(true)] out TValue? value)
Поэтому возникла необходимость в другом атрибуте.
Ответ или решение
В C# при использовании атрибутов NotNullWhen
и MaybeNullWhen
действительно существует разница, несмотря на то, что они могут показаться взаимозаменяемыми в некоторых контекстах. Давайте рассмотрим каждый из них более подробно.
Понимание атрибутов
-
NotNullWhen(true):
- Этот атрибут указывает, что если метод вернул
true
, то значение, переданное вout
параметр, будет не равноnull
. Это позволяет статическому анализатору понять, что в случае успешного выполнения операцииout
параметр гарантированно содержит ненулевое значение. - Пример использования:
public bool TryGetValue(TKey key, [NotNullWhen(true)] out TValue? value) { // реализация }
- Этот атрибут указывает, что если метод вернул
-
MaybeNullWhen(false):
- Этот атрибут, наоборот, указывает, что если метод вернул
false
, то значение в параметре может бытьnull
. Это говорит статическому анализатору, что если операция не удалась, то вы не можете полагаться на значение, переданное вout
параметр — оно может бытьnull
. - Пример использования:
public bool TryGetValue(TKey key, [MaybeNullWhen(false)] out TValue value) { // реализация }
- Этот атрибут, наоборот, указывает, что если метод вернул
Семантическое различие
Хотя визуально кажется, что оба атрибута описывают поведение параметров в зависимости от возвращаемого значения метода, их структура и семантика отличаются:
NotNullWhen(true)
акцентирует внимание на гарантии ненулевого значения при успешном результате, обеспечивая более строгую проверку.MaybeNullWhen(false)
обеспечивает более гибкий подход, позволяя вернутьnull
, если операция не удалась, без обязательства указывать нечто определённое.
Исторический контекст
Как вы правильно отметили, атрибуты NotNullWhen
и MaybeNullWhen
были введены в C# 8, когда поддержка референсной семантики с учетом нулевых значений еще не была полностью реализована. На момент ввода в эксплуатацию эти атрибуты решали проблему предоставления необходимой информации для статического анализа в условиях ограниченной поддержки нулевых значений.
Таким образом, основное отличие между ними заключается в их предназначении и то, как они интерпретируются статическими анализаторами:
NotNullWhen(true)
— гарантирует ненулевое значение при истинном результате.MaybeNullWhen(false)
— обозначает, что значение может бытьnull
в случае ложного результата.
Применение на практике
При проектировании API или библиотек, понимание различий между этими двумя атрибутами позволяет вам более эффективно передавать информацию о поведении методов конечным пользователям и предотвращать частые ошибки при работе с возможными значениями null
. Выбор правильного атрибута способствует ясности кода и позволяет избежать ненужных проверок на null
со стороны разработчиков.
Надеюсь, это разъяснение помогло вам лучше понять отличие между NotNullWhen(true)
и MaybeNullWhen(false)
в контексте C#.