Tipos que permitem valor nulo (referência do C#)

Um tipo de valor que pode ser anulado representa todos os valores de seu tipo de valor subjacente e um valor nulo adicional. Por exemplo, você pode atribuir qualquer um dos três valores a seguir a uma bool? variável: true, falseou null. Um tipo de valor subjacente não T pode ser um tipo de valor anulado em si.

Observação

O C# 8.0 introduz o recurso de tipos de referência que permitem valor nulo. Para obter mais informações, consulte Tipos de referência que podem ser anulados. Os tipos de valor que podem ser anulados estão disponíveis a partir do C# 2.

Qualquer tipo de valor que pode ser anulado é uma instância da estrutura System.Nullable<T> genérica. Você pode se referir a um tipo de valor que pode ser anulado com um tipo subjacente T em qualquer um dos seguintes formulários intercambiáveis: Nullable<T> ou T?.

Normalmente, você usa um tipo de valor que pode ser anulado quando precisa representar o valor indefinido de um tipo de valor subjacente. Por exemplo, uma variável booliana ou bool, só pode ser true ou false. No entanto, em alguns aplicativos, um valor de variável pode ser indefinido ou ausente. Por exemplo, um campo de banco true de dados pode conter ou falseou pode não conter nenhum valor, ou seja, NULL. Você pode usar o bool? tipo nesse cenário.

Declaração e atribuição

Como um tipo de valor é implicitamente conversível para o tipo de valor anulado correspondente, você pode atribuir um valor a uma variável de um tipo de valor que pode ser anulado como faria para seu tipo de valor subjacente. Você também pode atribuir o null valor. Por exemplo:

double? pi = 3.14;
char? letter = 'a';

int m2 = 10;
int? m = m2;

bool? flag = null;

// An array of a nullable value type:
int?[] arr = new int?[10];

O valor padrão de um tipo de valor nullanulado representa , ou seja, é uma instância cuja propriedade Nullable<T>.HasValue retorna false.

Exame de uma instância de um tipo de valor anulado

A partir do C# 7.0, null você pode usar o operador com um padrão de tipo para examinar uma instância de um tipo de valor que pode ser anulado e recuperar um valor de um tipo subjacente:

int? a = 42;
if (a is int valueOfA)
{
    Console.WriteLine($"a is {valueOfA}");
}
else
{
    Console.WriteLine("a does not have a value");
}
// Output:
// a is 42

Você sempre pode usar as seguintes propriedades somente leitura para examinar e obter um valor de uma variável de tipo de valor anulada:

O exemplo a seguir usa a HasValue propriedade para testar se a variável contém um valor antes de exibi-lo:

int? b = 10;
if (b.HasValue)
{
    Console.WriteLine($"b is {b.Value}");
}
else
{
    Console.WriteLine("b does not have a value");
}
// Output:
// b is 10

Você também pode comparar uma variável de um tipo de valor anulado com null em vez de usar HasValue a propriedade , como mostra o exemplo a seguir:

int? c = 7;
if (c != null)
{
    Console.WriteLine($"c is {c.Value}");
}
else
{
    Console.WriteLine("c does not have a value");
}
// Output:
// c is 7

Conversão de um tipo de valor que pode ser anulado em um tipo subjacente

Se você quiser atribuir um valor de um tipo de valor anulado a uma variável de tipo de valor não anulada, talvez seja necessário especificar o valor a ser atribuído no lugar de null. Use o operador de coalescing nulo para fazer isso (você também pode usar o Nullable<T>.GetValueOrDefault(T) método para a mesma finalidade):

int? a = 28;
int b = a ?? -1;
Console.WriteLine($"b is {b}");  // output: b is 28

int? c = null;
int d = c ?? -1;
Console.WriteLine($"d is {d}");  // output: d is -1

Se você quiser usar o valor padrão do tipo de valor subjacente no lugar de , use o Nullable<T>.GetValueOrDefault() método .

Você também pode lançar explicitamente um tipo de valor que pode ser anulado em um tipo não anulado, como mostra o exemplo a seguir:

int? n = null;

//int m1 = n;    // Doesn't compile
int n2 = (int)n; // Compiles, but throws an exception if n is null

Em tempo de operação, se o valor de um tipo de valor anulado for null, a cast explícita lançará um InvalidOperationException.

Um tipo de valor não anulado é T implicitamente conversível para o tipo de valor anulado correspondente T?.

Operadores suspensos

Os operadores unários e binários predefinidos ou quaisquer operadores sobrecarregados com suporte por um tipo de valor também têm suporte pelo tipo de valor anulado correspondente.T? Esses operadores, também conhecidos como operadores suspensos,nullproduzem se um ou ambos os operadores são ; caso contrário, o operador usa os valores contidos de seus operadores para calcular o resultado. Por exemplo:

int? a = 10;
int? b = null;
int? c = 10;

a++;        // a is 11
a = a * c;  // a is 110
a = a + b;  // a is null

Observação

Para o bool? tipo , os operadores predefinidos &| e não seguem as regras descritas nesta seção: o resultado de uma avaliação de operador pode ser não nulo, mesmo se um dos operadores for null. Para obter mais informações, confira a seção Operadores lógicos booleanos anuláveis do artigo Operadores lógicos boolianos.

Para os operadores de comparação, >, >=<=e , se um ou ambos os operands nullsão , falseo resultado é ; caso contrário, os valores contidos dos operativos serão comparados. Não presuma que como uma comparação (por exemplo, <=) retorna false, a comparação oposta (>) retorna true. O exemplo a seguir mostra que 10

  • nem maior ou igual a null
  • nem menor que null
int? a = 10;
Console.WriteLine($"{a} >= null is {a >= null}");
Console.WriteLine($"{a} < null is {a < null}");
Console.WriteLine($"{a} == null is {a == null}");
// Output:
// 10 >= null is False
// 10 < null is False
// 10 == null is False

int? b = null;
int? c = null;
Console.WriteLine($"null >= null is {b >= c}");
Console.WriteLine($"null == null is {b == c}");
// Output:
// null >= null is False
// null == null is True

Para o operador de igualdade, se ambos os operadores são , o resultado é , truese apenas um dos operands nullfor , falseo resultado será ; caso contrário, os valores contidos nulldos operadores serão comparados.

Para o operador de desigualdade,null se ambos os operadores são , o resultado é , falsenullse apenas um dos operadores for , trueo resultado será ; caso contrário, os valores contidos dos operadores serão comparados.

Se houver uma conversão definida pelo usuário entre dois tipos de valor, a mesma conversão também poderá ser usada entre os tipos de valor anuáveis correspondentes.

Conversão boxing e unboxing

Uma instância de um tipo de valor que T? pode ser T? da seguinte forma:

  • Se HasValue retorna false, a referência nula é produzida.
  • Se HasValue retornar true, o valor correspondente do tipo de valor subjacente T será a box, não a instância de Nullable<T>.

Você pode unboxar um valor de um tipo de valor para T o tipo de valor anulado correspondente T?, como mostra o exemplo a seguir:

int a = 41;
object aBoxed = a;
int? aNullable = (int?)aBoxed;
Console.WriteLine($"Value of aNullable: {aNullable}");

object aNullableBoxed = aNullable;
if (aNullableBoxed is int valueOfA)
{
    Console.WriteLine($"aNullableBoxed is boxed int: {valueOfA}");
}
// Output:
// Value of aNullable: 41
// aNullableBoxed is boxed int: 41

Como identificar um tipo de valor que pode ser anulado

O exemplo a seguir mostra como System.Type determinar se uma instância representa um tipo de valor que pode ser nulo construído, ou seja, System.Nullable<T> o tipo com um parâmetro de tipo especificado T:

Console.WriteLine($"int? is {(IsNullable(typeof(int?)) ? "nullable" : "non nullable")} value type");
Console.WriteLine($"int is {(IsNullable(typeof(int)) ? "nullable" : "non-nullable")} value type");

bool IsNullable(Type type) => Nullable.GetUnderlyingType(type) != null;

// Output:
// int? is nullable value type
// int is non-nullable value type

Como mostra o exemplo, você usa o operador typeof para criar uma instância.

Se você quiser determinar se uma instância é de um tipo de valor anulado, não use Object.GetTypeType o método para fazer com que uma instância seja testada com o código anterior. Quando você chama o Object.GetType método em uma instância de um tipo de valor anulado, a instância é Object.GetType para Object. Como a boxing de uma instância não nula de um tipo de valor anulado é equivalente à boxing de um valor do tipo subjacente, GetTypeType retorna uma instância que representa o tipo subjacente de um tipo de valor anulado:

int? a = 17;
Type typeOfA = a.GetType();
Console.WriteLine(typeOfA.FullName);
// Output:
// System.Int32

Além disso, não use o operador is para determinar se uma instância é de um tipo de valor que pode ser nulo. Como mostra o exemplo a seguir, não é possível distinguir tipos de uma instância de tipo de valor que pode ser anulada e sua instância de tipo subjacente com o is operador :

int? a = 14;
if (a is int)
{
    Console.WriteLine("int? instance is compatible with int");
}

int b = 17;
if (b is int?)
{
    Console.WriteLine("int instance is compatible with int?");
}
// Output:
// int? instance is compatible with int
// int instance is compatible with int?

Em vez disso Nullable.GetUnderlyingType , use o do primeiro exemplo e o Nullable.GetUnderlyingType para verificar se uma instância é de um tipo de valor anulado.

Observação

Os métodos descritos nesta seção não são aplicáveis no caso de tipos de referência que podem ser anulados.

Especificação da linguagem C#

Para obter mais informações, confira as seguintes seções da especificação da linguagem C#:

Veja também