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


! — оператор (допускающий значение NULL) (справочник по C#)

Унарный оператор постфикса ! — это оператор null-forgiving, или null-подавление. В включённом контексте аннотаций допускающих значение NULL, вы используете оператор null-forgiving для подавления всех предупреждений о допустимости NULL для предыдущего выражения. Унарный префиксный оператор ! является оператором логического отрицания. Оператор, допускающий NULL, ни на что не влияет во время выполнения. Он влияет только на статический анализ потока компилятора путем изменения состояния NULL выражения. Во время выполнения выражение x! сравнивается с результатом базового выражения x.

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

Примеры

Один из вариантов использования оператора, допускающего значение NULL, — тестирование логики проверки аргументов. Например, рассмотрим следующий класс.

#nullable enable
public class Person
{
    public Person(string name) => Name = name ?? throw new ArgumentNullException(nameof(name));

    public string Name { get; }
}

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

[TestMethod, ExpectedException(typeof(ArgumentNullException))]
public void NullNameShouldThrowTest()
{
    var person = new Person(null!);
}

Без оператора, допускающего значение NULL, компилятор создает следующее предупреждение для предыдущего кода: Warning CS8625: Cannot convert null literal to non-nullable reference type. Используя оператор, допускающий значение NULL, вы сообщаете компилятору, что передача null ожидается и что о ней не нужно предупреждать.

Вы также можете использовать оператор подавления null, если вы точно знаете, что выражение не может быть null, но компилятор не может распознать это. В следующем примере, если метод IsValid возвращает true, его аргумент не является null, и его можно безопасно разыменовать:

public static void Main()
{
    Person? p = Find("John");
    if (IsValid(p))
    {
        Console.WriteLine($"Found {p!.Name}");
    }
}

public static bool IsValid(Person? person)
    => person is not null && person.Name is not null;

Без оператора, допускающего значение NULL, компилятор создает следующее предупреждение для кода p.Name: Warning CS8602: Dereference of a possibly null reference.

Если вы можете изменить метод IsValid, можно использовать атрибут NotNullWhen для указания компилятору, что аргумент метода IsValid не может быть null, если метод возвращает true.

public static void Main()
{
    Person? p = Find("John");
    if (IsValid(p))
    {
        Console.WriteLine($"Found {p.Name}");
    }
}

public static bool IsValid([NotNullWhen(true)] Person? person)
    => person is not null && person.Name is not null;

В предыдущем примере не требуется использовать оператор, прощающий null, так как компилятор имеет достаточно сведений, чтобы определить, что p не может находиться null внутри инструкции if. См. сведения об атрибутах, позволяющих указать дополнительную информацию о состоянии NULL для переменной, в руководстве по включению в API атрибутов для определения ожидаемых значений NULL.

Спецификация языка C#

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

См. также