Tipos de referência anuláveisNullable reference types

O C# 8.0 apresenta tipos de referência que permitem valor nulo e tipos de referência que não permitem valor nulo que permitem que você crie importantes instruções sobre as propriedades para variáveis de tipo de referência:C# 8.0 introduces nullable reference types and non-nullable reference types that enable you to make important statements about the properties for reference type variables:

  • Uma referência não deve ser nula.A reference isn't supposed to be null. Quando variáveis não devem ser nulas, o compilador impõe regras que garantem que é seguro desreferenciar essas variáveis sem primeiro verificar se ela não é nula:When variables aren't supposed to be null, the compiler enforces rules that ensure it's safe to dereference these variables without first checking that it isn't null:
    • A variável deve ser inicializada para um valor não nulo.The variable must be initialized to a non-null value.
    • A variável nunca pode receber o valor null.The variable can never be assigned the value null.
  • Uma referência pode ser nula.A reference may be null. Quando variáveis puderem ser nulas, o compilador imporá diferentes regras para garantir que você verificou corretamente se há uma referência nula:When variables may be null, the compiler enforces different rules to ensure that you've correctly checked for a null reference:
    • a variável só poderá ser desreferenciada quando o compilador puder garantir que o valor não é nulo.The variable may only be dereferenced when the compiler can guarantee that the value isn't null.
    • Essas variáveis podem ser inicializadas com o valor null padrão e receber o valor null em outro código.These variables may be initialized with the default null value and may be assigned the value null in other code.

Esse novo recurso fornece benefícios significativos em relação ao tratamento de variáveis de referência em versões anteriores do C#, em que a intenção de design não pode ser determinada a partir da declaração de variável.This new feature provides significant benefits over the handling of reference variables in earlier versions of C# where the design intent can't be determined from the variable declaration. O compilador não forneceu segurança com relação a exceções de referência nula para tipos de referência:The compiler didn't provide safety against null reference exceptions for reference types:

  • Uma referência pode ser nula.A reference can be null. O compilador não emite avisos quando uma variável do tipo de referência é inicializada null ou posteriormente atribuída null .The compiler doesn't issue warnings when a reference-type variable is initialized to null, or later assigned null. O compilador emite avisos quando essas variáveis são desreferenciadas sem verificações nulas.The compiler issues warnings when these variables are dereferenced without null checks.
  • Uma referência é considerada não nula.A reference is assumed to be not null. O compilador não emite nenhum aviso quando os tipos de referência são desreferenciados.The compiler doesn't issue any warnings when reference types are dereferenced. O compilador emite avisos se uma variável é definida como uma expressão que pode ser nula.The compiler issues warnings if a variable is set to an expression that may be null.

Esses avisos são emitidos no momento da compilação.These warnings are emitted at compile time. O compilador não adiciona nenhuma verificação nula ou outras construções de tempo de execução em um contexto anulável.The compiler doesn't add any null checks or other runtime constructs in a nullable context. Em tempo de execução, uma referência anulável e uma referência não anulável são equivalentes.At runtime, a nullable reference and a non-nullable reference are equivalent.

Com a adição de tipos de referência que permitem valor nulo, é possível declarar sua intenção mais claramente.With the addition of nullable reference types, you can declare your intent more clearly. O valor null é a maneira correta de representar que uma variável não se refere a um valor.The null value is the correct way to represent that a variable doesn't refer to a value. Não use esse recurso para remover todos os valores null do seu código.Don't use this feature to remove all null values from your code. Em vez disso, você deve declarar sua intenção par ao compilador e para outros desenvolvedores que leem seu código.Rather, you should declare your intent to the compiler and other developers that read your code. Ao declarar sua intenção, o compilador informa quando você escreve um código inconsistente com essa intenção.By declaring your intent, the compiler informs you when you write code that is inconsistent with that intent.

Um tipo de referência que permite valor nulo é indicado usando a mesma sintaxe que tipos de valor que permitem valor nulo: um ? é acrescentado ao tipo da variável.A nullable reference type is noted using the same syntax as nullable value types: a ? is appended to the type of the variable. Por exemplo, a seguinte declaração de variável representa uma variável de cadeia de caracteres que permite valor nulo, name:For example, the following variable declaration represents a nullable string variable, name:

string? name;

Qualquer variável em que o ? não seja acrescentado ao nome do tipo é um tipo de referência não anulável.Any variable where the ? isn't appended to the type name is a non-nullable reference type. Isso inclui todas as variáveis de tipo de referência no código existente quando você habilitou esse recurso.That includes all reference type variables in existing code when you've enabled this feature.

O compilador usa uma análise estática para determinar se uma referência que permite valor nulo é conhecida como não nula.The compiler uses static analysis to determine if a nullable reference is known to be non-null. O compilador informa se você desreferencia uma referência quer permite valor nulo quando ela pode ser nula.The compiler warns you if you dereference a nullable reference when it may be null. Você pode substituir esse comportamento usando o operador NULL-tolerante ! seguindo um nome de variável.You can override this behavior by using the null-forgiving operator ! following a variable name. Por exemplo, se você sabe que a variável name não é nula, mas o compilador emite um aviso, é possível escrever o seguinte código para substituir a análise do compilador:For example, if you know the name variable isn't null but the compiler issues a warning, you can write the following code to override the compiler's analysis:

name!.Length;

Possibilidade de nulidade de tiposNullability of types

Qualquer tipo de referência pode ter uma das quatro nulidades, que descreve quando os avisos são gerados:Any reference type can have one of four nullabilities, which describes when warnings are generated:

  • Não nulo: nulo não pode ser atribuído a variáveis deste tipo.Nonnullable: Null can't be assigned to variables of this type. As variáveis desse tipo não precisam ser verificadas quanto à nulidade antes de desreferenciar.Variables of this type don't need to be null-checked before dereferencing.
  • Nullable: NULL pode ser atribuído a variáveis desse tipo.Nullable: Null can be assigned to variables of this type. Desreferenciar variáveis desse tipo sem verificar primeiro se há null gera um aviso.Dereferencing variables of this type without first checking for null causes a warning.
  • Alheios: alheios é o estado de pré-C # 8,0.Oblivious: Oblivious is the pre-C# 8.0 state. As variáveis desse tipo podem ser desreferenciadas ou atribuídas sem avisos.Variables of this type can be dereferenced or assigned without warnings.
  • Desconhecido: desconhecido é geralmente para parâmetros de tipo em que as restrições não dizem ao compilador que o tipo deve ser anulável ou não nulo.Unknown: Unknown is generally for type parameters where constraints don't tell the compiler that the type must be nullable or nonnullable.

A nulidade de um tipo em uma declaração de variável é controlada pelo contexto que permite valor nulo no qual a variável é declarada.The nullability of a type in a variable declaration is controlled by the nullable context in which the variable is declared.

Contextos que permitem valor nuloNullable contexts

Contextos que permitem valor nulo habilitam o controle refinado para a maneira como o compilador interpreta variáveis de tipo de referência.Nullable contexts enable fine-grained control for how the compiler interprets reference type variables. O contexto de anotação anulável de qualquer linha de origem determinada é habilitado ou desabilitado.The nullable annotation context of any given source line is either enabled or disabled. Você pode considerar o compilador pré-C # 8,0 como compilar todo o seu código em um contexto anulável desabilitado: qualquer tipo de referência pode ser nulo.You can think of the pre-C# 8.0 compiler as compiling all your code in a disabled nullable context: any reference type may be null. O contexto de avisos anuláveis também pode ser habilitado ou desabilitado.The nullable warnings context may also be enabled or disabled. O contexto de avisos que permite valor nulo especifica os avisos gerados pelo compilador usando sua análise de fluxo.The nullable warnings context specifies the warnings generated by the compiler using its flow analysis.

O contexto de anotação anulável e o contexto de aviso anulável podem ser definidos para um projeto usando o Nullable elemento em seu arquivo . csproj .The nullable annotation context and nullable warning context can be set for a project using the Nullable element in your .csproj file. Esse elemento configura como o compilador interpreta a nulidade de tipos e quais avisos são gerados.This element configures how the compiler interprets the nullability of types and what warnings are generated. As configurações válidas são:Valid settings are:

  • enable: O contexto de anotação anulável está habilitado.enable: The nullable annotation context is enabled. O contexto de aviso que permite valor nulo está habilitado.The nullable warning context is enabled.
    • Variáveis de um tipo de referência, string por exemplo, não permitem valor nulo.Variables of a reference type, string for example, are non-nullable. Todos os avisos de nulidade estão habilitados.All nullability warnings are enabled.
  • warnings: O contexto de anotação anulável está desabilitado.warnings: The nullable annotation context is disabled. O contexto de aviso que permite valor nulo está habilitado.The nullable warning context is enabled.
    • As variáveis de um tipo de referência são óbvias.Variables of a reference type are oblivious. Todos os avisos de nulidade estão habilitados.All nullability warnings are enabled.
  • annotations: O contexto de anotação anulável está habilitado.annotations: The nullable annotation context is enabled. O contexto de aviso que permite valor nulo está desabilitado.The nullable warning context is disabled.
    • Variáveis de um tipo de referência, String, por exemplo, são não anuláveis.Variables of a reference type, string for example, are non-nullable. Todos os avisos de nulidade estão desabilitados.All nullability warnings are disabled.
  • disable: O contexto de anotação anulável está desabilitado.disable: The nullable annotation context is disabled. O contexto de aviso que permite valor nulo está desabilitado.The nullable warning context is disabled.
    • As variáveis de um tipo de referência são alheias, como as versões anteriores do C#.Variables of a reference type are oblivious, just like earlier versions of C#. Todos os avisos de nulidade estão desabilitados.All nullability warnings are disabled.

Exemplo:Example:

<Nullable>enable</Nullable>

Também é possível usar diretivas para definir esses mesmos contextos em qualquer lugar no seu projeto:You can also use directives to set these same contexts anywhere in your project:

  • #nullable enable: Define o contexto de anotação anulável e o contexto de aviso anulável como habilitado.#nullable enable: Sets the nullable annotation context and nullable warning context to enabled.
  • #nullable disable: Define o contexto de anotação anulável e o contexto de aviso anulável como desabilitado.#nullable disable: Sets the nullable annotation context and nullable warning context to disabled.
  • #nullable restore: Restaura o contexto de anotação anulável e o contexto de aviso anulável para as configurações do projeto.#nullable restore: Restores the nullable annotation context and nullable warning context to the project settings.
  • #nullable disable warnings: Defina o contexto de aviso anulável como desabilitado.#nullable disable warnings: Set the nullable warning context to disabled.
  • #nullable enable warnings: Defina o contexto de aviso anulável como habilitado.#nullable enable warnings: Set the nullable warning context to enabled.
  • #nullable restore warnings: Restaura o contexto de aviso anulável para as configurações do projeto.#nullable restore warnings: Restores the nullable warning context to the project settings.
  • #nullable disable annotations: Defina o contexto de anotação anulável como desabilitado.#nullable disable annotations: Set the nullable annotation context to disabled.
  • #nullable enable annotations: Defina o contexto de anotação anulável como habilitado.#nullable enable annotations: Set the nullable annotation context to enabled.
  • #nullable restore annotations: Restaura o contexto de aviso de anotação para as configurações do projeto.#nullable restore annotations: Restores the annotation warning context to the project settings.

Importante

O contexto anulável global não se aplica a arquivos de código gerados.The global nullable context does not apply for generated code files. Em qualquer estratégia, o contexto anulável é desabilitado para qualquer arquivo de origem marcado como gerado.Under either strategy, the nullable context is disabled for any source file marked as generated. Isso significa que qualquer API em arquivos gerados não é anotada.This means any APIs in generated files are not annotated. Há quatro maneiras de um arquivo ser marcado como gerado:There are four ways a file is marked as generated:

  1. Em. editorconfig, especifique generated_code = true em uma seção que se aplica a esse arquivo.In the .editorconfig, specify generated_code = true in a section that applies to that file.
  2. Put <auto-generated> ou <auto-generated/> em um comentário na parte superior do arquivo.Put <auto-generated> or <auto-generated/> in a comment at the top of the file. Ele pode estar em qualquer linha nesse comentário, mas o bloco de comentário deve ser o primeiro elemento no arquivo.It can be on any line in that comment, but the comment block must be the first element in the file.
  3. Inicie o nome do arquivo com TemporaryGeneratedFile_Start the file name with TemporaryGeneratedFile_
  4. Termine o nome do arquivo com . designer.cs, . generated.cs, . g.cs ou . g.i.cs.End the file name with .designer.cs, .generated.cs, .g.cs, or .g.i.cs.

Os geradores podem optar por usar a #nullable diretiva de pré-processador.Generators can opt-in using the #nullable preprocessor directive.

Por padrão, os contextos de anotação e de aviso anuláveis são desabilitados, incluindo novos projetos.By default, nullable annotation and warning contexts are disabled, including new projects. Isso significa que o código existente é compilado sem alterações e sem gerar nenhum aviso novo.That means that your existing code compiles without changes and without generating any new warnings.

Essas opções fornecem duas estratégias distintas para atualizar uma base de código existente para usar tipos de referência anuláveis.These options provide two distinct strategies to update an existing codebase to use nullable reference types.

Contexto de anotação que permite valor nuloNullable annotation context

O compilador usa as seguintes regras em um contexto de anotação que permite valor nulo desabilitado:The compiler uses the following rules in a disabled nullable annotation context:

  • Não é possível declarar referências que permitem valor nulo em um contexto desabilitado.You can't declare nullable references in a disabled context.
  • Todas as variáveis de referência podem ser atribuídas a um valor nulo.All reference variables may be assigned a value of null.
  • Nenhum aviso é gerado quando uma variável de um tipo de referência é desreferenciado.No warnings are generated when a variable of a reference type is dereferenced.
  • O operador tolerante a nulo pode não ser usado em um contexto desabilitado.The null-forgiving operator may not be used in a disabled context.

O comportamento é o mesmo que o das versões anteriores de C#.The behavior is the same as previous versions of C#.

O compilador usa as seguintes regras em um contexto de anotação que permite valor nulo habilitado:The compiler uses the following rules in an enabled nullable annotation context:

  • Qualquer variável de um tipo de referência é uma referência que não permite valor nulo.Any variable of a reference type is a non-nullable reference.
  • Qualquer referência que não permite valor nulo pode ser desreferenciada com segurança.Any non-nullable reference may be dereferenced safely.
  • Qualquer tipo de referência que permite valor nulo (indicado pelo ? após o tipo na declaração de variável) pode ser nulo.Any nullable reference type (noted by ? after the type in the variable declaration) may be null. A análise estática determina se o valor é conhecido como não nulo quando é desreferenciado.Static analysis determines if the value is known to be non-null when it's dereferenced. Caso contrário, o compilador avisa.If not, the compiler warns you.
  • É possível usar o operador tolerante a nulo para declarar que uma referência que permite valor nulo não é nula.You can use the null-forgiving operator to declare that a nullable reference isn't null.

Em um contexto de anotação que permite valor nulo habilitado, o caractere ? acrescentado a um tipo de referência declara um tipo de referência que permite valor nulo.In an enabled nullable annotation context, the ? character appended to a reference type declares a nullable reference type. O operador NULL-tolerante ! pode ser anexado a uma expressão para declarar que a expressão não é nula.The null-forgiving operator ! may be appended to an expression to declare that the expression isn't null.

Contexto de aviso que permite valor nuloNullable warning context

O contexto de aviso que permite valor nulo é diferente do contexto de anotação que permite valor nulo.The nullable warning context is distinct from the nullable annotation context. Os avisos podem ser habilitados mesmo quando as novas anotações estão desabilitadas.Warnings can be enabled even when the new annotations are disabled. O compilador usa a análise de fluxo estática para determinar o estado nulo de qualquer referência.The compiler uses static flow analysis to determine the null state of any reference. O estado nulo é não nulo ou talvez nulo quando o contexto de aviso que permite valor nulo não está desabilitado.The null state is either not null or maybe null when the nullable warning context isn't disabled. Se você desreferenciar uma referência quando o compilador tiver determinado que ela é talvez nula, o compilador avisará.If you dereference a reference when the compiler has determined it's maybe null, the compiler warns you. O estado de uma referência é talvez nulo, a menos que o compilador possa determinar uma das duas condições:The state of a reference is maybe null unless the compiler can determine one of two conditions:

  1. Definitivamente, a variável foi atribuída a um valor não nulo.The variable has been definitely assigned a non-null value.
  2. A variável ou expressão foi marcada novamente como nula antes de desreferenciá-la.The variable or expression has been checked against null before de-referencing it.

O compilador gera avisos ao desreferenciar uma variável ou expressão que talvez seja nula em um contexto de aviso anulável.The compiler generates warnings when you dereference a variable or expression that is maybe null in a nullable warning context. Além disso, o compilador gera avisos quando uma variável de tipo de referência não nula é atribuída a uma variável or a uma expressão nula em um contexto de anotação anulável habilitado.Furthermore, the compiler generates warnings when a nonnullable reference-type variable is assigned a maybe null variable or expression in an enabled nullable annotation context.

Atributos descrevem APIsAttributes describe APIs

Você adiciona atributos a APIs que fornecem ao compilador mais informações sobre quando argumentos ou valores de retorno podem ou não ser nulos.You add attributes to APIs that provide the compiler more information about when arguments or return values can or can't be null. Você pode aprender mais sobre esses atributos em nosso artigo na referência de linguagem que abrange os atributos anuláveis.You can learn more about these attributes in our article in the language reference covering the nullable attributes. Esses atributos estão sendo adicionados às bibliotecas do .NET em versões atuais e futuras.These attributes are being added to .NET libraries over current and upcoming releases. As APIs usadas com mais frequência estão sendo atualizadas primeiro.The most commonly used APIs are being updated first.

Armadilhas conhecidasKnown pitfalls

Matrizes e structs que contêm tipos de referência são armadilhas conhecidas no recurso de tipos de referência anulável.Arrays and structs that contain reference types are known pitfalls in nullable reference types feature.

EstruturasStructs

Uma struct que contém tipos de referência não anuláveis permite atribuir default a ela sem nenhum aviso.A struct that contains non-nullable reference types allows assigning default for it without any warnings. Considere o exemplo a seguir:Consider the following example:

using System;

#nullable enable

public struct Student
{
    public string FirstName;
    public string? MiddleName;
    public string LastName;
}

public static class Program
{
    public static void PrintStudent(Student student)
    {
        Console.WriteLine($"First name: {student.FirstName.ToUpper()}");
        Console.WriteLine($"Middle name: {student.MiddleName.ToUpper()}");
        Console.WriteLine($"Last name: {student.LastName.ToUpper()}");
    }

    public static void Main() => PrintStudent(default);
}

No exemplo anterior, não há nenhum aviso no PrintStudent(default) enquanto os tipos de referência não anuláveis FirstName e LastName são nulos.In the preceding example, there is no warning in PrintStudent(default) while the non-nullable reference types FirstName and LastName are null.

Outro caso mais comum é quando você lida com structs genéricos.Another more common case is when you deal with generic structs. Considere o exemplo a seguir:Consider the following example:

#nullable enable

public struct Foo<T>
{
    public T Bar { get; set; }
}

public static class Program
{
    public static void Main()
    {
        string s = default(Foo<string>).Bar;
    }
}

No exemplo anterior, a propriedade será Bar null em tempo de execução e será atribuída a uma cadeia de caracteres não anulável sem nenhum aviso.In the preceding example, the property Bar is going to be null at runtime, and it's assigned to non-nullable string without any warnings.

MatrizesArrays

As matrizes são também uma armadilha conhecida em tipos de referência anuláveis.Arrays are also a known pitfall in nullable reference types. Considere o exemplo a seguir, que não produz nenhum aviso:Consider the following example which doesn't produce any warnings:

using System;

#nullable enable

public static class Program
{
    public static void Main()
    {
        string[] values = new string[10];
        string s = values[0];
        Console.WriteLine(s.ToUpper());
    }
}

No exemplo anterior, a declaração da matriz mostra que ela contém cadeias de caracteres não anuláveis, enquanto seus elementos são todos inicializados como NULL.In the preceding example, the declaration of the array shows it holds non-nullable strings, while its elements are all initialized to null. Em seguida, a variável s recebe um valor nulo (o primeiro elemento da matriz).Then, the variable s is assigned a null value (the first element of the array). Por fim, a variável s é desreferenciada causando uma exceção de tempo de execução.Finally, the variable s is dereferenced causing a runtime exception.

Confira tambémSee also