! ! (tolerante a nulo) operador (referência do C#)

O operador ! de sufixo unário é o operador tolerante a nulo ou de supressão de nulo. Em um contexto de anotação nulo habilitado, você usa o operador de tolerância nula para suprimir todos os avisos anuláveis para a expressão anterior. O operador ! de prefixo unário é o operador de negação lógica. O operador tolerante a nulo não tem efeito em tempo de execução. Ele afeta apenas a análise de fluxo estático do compilador alterando o estado nulo da expressão. Em tempo de execução, a expressão x! é avaliada como o resultado da expressão xsubjacente.

Para obter mais informações sobre o recurso de tipos de referência que permitem valor nulo, consulte Tipos de referência que permitem valor nulo.

Exemplos

Um dos casos de uso do operador tolerante a nulo está em testar a lógica de validação do argumento. Por exemplo, considere a seguinte classe:

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

    public string Name { get; }
}

Usando a estrutura de teste MSTest, você pode criar o seguinte teste para a lógica de validação no construtor:

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

Sem o operador tolerante a nulo, o compilador gera o seguinte aviso para o código anterior: Warning CS8625: Cannot convert null literal to non-nullable reference type. Ao usar o operador tolerante a nulo, informe ao compilador que a passagem null é esperada e não deve ser avisada.

Você também pode usar o operador de tolerância nula se souber definitivamente que uma expressão não pode ser null, mas o compilador não consegue reconhecer isso. No exemplo a seguir, se o método IsValid retornar true, seu argumento não será null e você poderá desreferenciá-lo com segurança:

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;

Sem o operador tolerante a nulo, o compilador gera o seguinte aviso para o código p.Name: Warning CS8602: Dereference of a possibly null reference.

Se você puder modificar o método IsValid, poderá usar o atributo NotNullWhen para informar ao compilador que um argumento do método IsValid não pode ser null quando o método retornar 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;

No exemplo anterior, você não precisa usar o operador de tolerância nula porque o compilador tem informações suficientes para descobrir que p não pode ser null dentro da instrução if. Para obter mais informações sobre os atributos que permitem fornecer informações adicionais sobre o estado nulo de uma variável, consulte As APIs de Atualização com atributos para definir expectativas quanto a nulos.

Especificação da linguagem C#

Para obter mais informações, consulte a seção Operador tolerante a nulo do Rascunho da especificação de tipos de referência que permitem valor nulo.

Confira também