Tipos de valor anulável (referência C#)
Um tipo T?
de valor anulável representa todos os valores de seu tipo T
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
, false
, ou null
. Um tipo T
de valor subjacente não pode ser um tipo de valor anulável em si.
Qualquer tipo de valor anulável é uma instância da estrutura genérica System.Nullable<T> . Você pode fazer referência a um tipo de valor anulável com um tipo T
subjacente em qualquer uma das seguintes formas intercambiáveis: Nullable<T>
ou T?
.
Normalmente, você usa um tipo de valor anulável quando precisa representar o valor indefinido de um tipo de valor subjacente. Por exemplo, uma variável booleana, ou bool
, só pode ser uma true
ou false
. No entanto, em alguns aplicativos, um valor de variável pode estar indefinido ou ausente. Por exemplo, um campo de banco de dados pode conter true
ou false
, ou pode não conter nenhum valor, ou seja, NULL
. Você pode usar o bool?
tipo nesse cenário.
Declaração e cessão
Como um tipo de valor é implicitamente conversível para o tipo de valor anulável correspondente, você pode atribuir um valor a uma variável de um tipo de valor anulável 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 anulável representa null
, ou seja, é uma instância cuja Nullable<T>.HasValue propriedade retorna false
.
Exame de uma instância de um tipo de valor anulável
Você pode usar o is
operador com um padrão de tipo para examinar uma instância de um tipo de valor anulável e null
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 anulável:
Nullable<T>.HasValue Indica se uma instância de um tipo de valor anulável tem um valor de seu tipo subjacente.
Nullable<T>.Value obtém o valor de um tipo subjacente se HasValue for
true
. Se HasValue forfalse
, a Value propriedade lança um InvalidOperationExceptionarquivo .
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 anulável com null
em vez de usar a HasValue
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 anulável para um tipo subjacente
Se desejar atribuir um valor de um tipo de valor anulável a uma variável de tipo de valor não anulável, talvez seja necessário especificar o valor a ser atribuído no lugar de null
. Use o operador ??
null-coalescing 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 null
, use o Nullable<T>.GetValueOrDefault() método.
Você também pode converter explicitamente um tipo de valor anulável para um tipo não anulável, 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 execução, se o valor de um tipo de valor anulável for null
, o cast explícito lançará um InvalidOperationExceptionarquivo .
Um tipo T
de valor não anulável é implicitamente conversível para o tipo T?
de valor anulável correspondente.
Operadores de elevadores
Os operadores unários e binários predefinidos ou quaisquer operadores sobrecarregados que são suportados por um tipo T
de valor também são suportados pelo tipo T?
de valor anulável correspondente. Esses operadores, também conhecidos como operadores levantados, produzem null
se um ou ambos os operandos são null
, caso contrário, o operador usa os valores contidos de seus operandos 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
Nota
Para o bool?
tipo, os operadores predefinidos &
e |
não seguem as regras descritas nesta seção: o resultado de uma avaliação do operador pode ser não-nulo, mesmo que um dos operandos seja null
. Para obter mais informações, consulte a seção Operadores lógicos booleanos anuláveis do artigo Operadores lógicos booleanos.
Para os operadores <
de comparação , >
, <=
, e >=
, se um ou ambos os operandos forem null
, o resultado é false
; caso contrário, os valores contidos dos operandos são comparados. Não assuma que, porque uma determinada comparação (por exemplo, <=
) retorna false
, a comparação oposta (>
) retorna true
. O exemplo a seguir mostra que 10 é
- nem superior nem igual a
null
- nem inferior a
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 operandos forem null
, o resultado é true
, se apenas um dos operandos for null
, o resultado é false
; caso contrário, os valores contidos dos operandos são comparados.
Para o operador !=
de desigualdade, se ambos os operandos forem null
, o resultado é false
, se apenas um dos operandos for null
, o resultado é true
; caso contrário, os valores contidos dos operandos são comparados.
Se existir uma conversão definida pelo usuário entre dois tipos de valor, a mesma conversão também pode ser usada entre os tipos de valor anuláveis correspondentes.
Boxe e unboxing
Uma instância de um tipo T?
de valor anulável é encaixotada da seguinte forma:
- Se HasValue retornar
false
, a referência nula será produzida. - Se HasValue retornar
true
, o valor correspondente do tipoT
de valor subjacente será colocado em caixa, não a instância de Nullable<T>.
Você pode descompactar um valor em caixa de um tipo T
de valor para o tipo T?
de valor anulável correspondente, 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 anulável
O exemplo a seguir mostra como determinar se uma System.Type instância representa um tipo de valor nulo construído, ou seja, o System.Nullable<T> tipo com um parâmetro T
type especificado:
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 System.Type instância.
Se você quiser determinar se uma instância é de um tipo de valor anulável, não use o Object.GetType método para obter uma Type instância a ser testada com o código anterior. Quando você chama o Object.GetType método em uma instância de um tipo de valor anulável, a instância é encaixotada como Object. Como o boxing de uma instância não nula de um tipo de valor anulável é equivalente ao boxing de um valor do tipo subjacente, GetType retorna uma Type instância que representa o tipo subjacente de um tipo de valor anulável:
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 anulável. Como mostra o exemplo a seguir, não é possível distinguir tipos de uma instância de tipo de valor anulável 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, use o Nullable.GetUnderlyingType operador from the first example e typeof para verificar se uma instância é de um tipo de valor anulável.
Nota
Os métodos descritos nesta secção não são aplicáveis no caso de tipos de referência anuláveis.
Especificação da linguagem C#
Para obter mais informações, consulte as seguintes seções da especificação da linguagem C#:
- Tipos anuláveis
- Operadores de elevadores
- Conversões anuláveis implícitas
- Conversões anuláveis explícitas
- Operadores de conversão levantados