В чем разница между NotNullWhen(true) и MaybeNullWhen(false)

Вопрос или проблема

Я большой поклонник шаблона 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 действительно существует разница, несмотря на то, что они могут показаться взаимозаменяемыми в некоторых контекстах. Давайте рассмотрим каждый из них более подробно.

Понимание атрибутов

  1. NotNullWhen(true):

    • Этот атрибут указывает, что если метод вернул true, то значение, переданное в out параметр, будет не равно null. Это позволяет статическому анализатору понять, что в случае успешного выполнения операции out параметр гарантированно содержит ненулевое значение.
    • Пример использования:
      public bool TryGetValue(TKey key, [NotNullWhen(true)] out TValue? value)
      {
       // реализация
      }
  2. 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#.

Оцените материал
Добавить комментарий

Капча загружается...