Types valeur pouvant accepter la valeur Null (référence C#)

Un type valeur pouvant accepter la valeur Null T? représente toutes les valeurs de son type valeur T sous-jacent et une valeur Null supplémentaire. Par exemple, vous pouvez affecter l’une des trois valeurs suivantes à une bool? variable : true, falseou null. Un type T de valeur sous-jacent ne peut pas être un type de valeur nullable lui-même.

Tout type de valeur nullable est une instance de la structure générique System.Nullable<T>. Vous pouvez faire référence à un type valeur nullable avec un type T sous-jacent dans l’un des formulaires interchangeables suivants : Nullable<T> ou T?.

Généralement, vous utilisez un type valeur nullable lorsque vous avez besoin de représenter la valeur non définie d’un type valeur sous-jacent. Par exemple, une variable booléenne ou bool, ne peut être que true ou false. Toutefois, dans certaines applications, une valeur de variable peut être non définie ou manquante. Par exemple, un champ de base de données peut contenir true ou false, ou il peut ne contenir aucune valeur, c’est-à-dire NULL. Vous pouvez utiliser le type bool? dans ce scénario.

Déclaration et affectation

Comme un type valeur est implicitement convertible en type valeur nullable correspondant, vous pouvez assigner une valeur à une variable d’un type valeur nullable comme vous le feriez pour son type valeur sous-jacent. Vous pouvez également affecter la valeur null. Par exemple :

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];

La valeur par défaut d’un type valeur nullable représente null, c’est-à-dire qu’il s’agit d’une instance dont la propriété Nullable<T>.HasValue retourne false.

Examen d’une instance d’un type valeur nullable

Vous pouvez utiliser l’opérateur is avec un modèle de type pour examiner une instance d’un type valeur nullable pour null et récupérer une valeur d’un type sous-jacent :

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

Vous pouvez toujours utiliser les propriétés en lecture seule suivantes pour examiner et obtenir une valeur d’une variable de type valeur nullable :

L’exemple suivant utilise la propriété HasValue pour tester si la variable contient une valeur avant de l’afficher :

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

Vous pouvez également comparer une variable de type nullable avec null au lieu d’utiliser la propriété HasValue, comme le montre l’exemple suivant :

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

Conversion d’un type valeur nullable en type sous-jacent

Si vous souhaitez affecter une valeur d’un type valeur nullable à une variable de type valeur non nullable, vous devrez peut-être spécifier la valeur à attribuer à la place de null. Utilisez l’opérateur de coalescence nulle?? pour ce faire (vous pouvez également utiliser la méthode Nullable<T>.GetValueOrDefault(T) dans le même but) :

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

Si vous souhaitez utiliser la valeur par défaut du type valeur sous-jacent à la place de null, utilisez la méthode Nullable<T>.GetValueOrDefault().

Vous pouvez également convertir explicitement un type valeur nullable en type non nullable, comme le montre l’exemple suivant :

int? n = null;

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

Au moment de l’exécution, si la valeur d’un type nullable estnull, le cast explicite lève uneInvalidOperationException.

Un type valeur non-nullable T est implicitement converti en type valeur nullable correspondant T?.

Opérateurs levés

Les opérateurs unaires et binaires prédéfinis ou tous les opérateurs surchargés pris en charge par un type valeur T sont également pris en charge par le type de valeur nullable T? correspondant. Ces opérateurs, également appelés opérateurs levés produisent null si l’un des opérandes ou les deux sont null ; sinon, l’opérateur utilise les valeurs contenues de ses opérandes pour calculer le résultat. Par exemple :

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

Notes

Pour le type bool?, les opérateurs & et | prédéfinis ne suivent pas les règles décrites dans cette section : le résultat d’une évaluation peut être non null, même si l’un des opérandes est null. Pour plus d’informations, voir la section Opérateurs logiques booléens Nullable de l’article Opérateurs logiques booléens.

Pour les opérateurs de comparaison <, >, <= et >=, si un ou les deux opérandes sont null, le résultat est false ; sinon, les valeurs contenues des opérandes sont comparées. Ne partez pas du principe que parce qu’une comparaison spécifique (par exemple <=) retourne false, la comparaison opposée (>) retourne true. L’exemple suivant montre que 10 n’est

  • ni supérieur ou égal à null
  • ni inférieur à 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

Pour l’opérateur d’égalité ==, si les deux opérandes sont null, le résultat est true, et si une seule des opérandes est null, le résultat est false ; sinon, les valeurs contenues des opérandes sont comparées.

Pour l’opérateur d’égalité !=, si les deux opérandes sont null, le résultat est false et si un seul des opérandes est null, le résultat est true ; sinon, les valeurs contenues des opérandes sont comparées.

S’il existe une conversion définie par l’utilisateur entre deux types de valeurs, la même conversion peut également être utilisée entre les types de valeurs nullables correspondants.

Boxing et unboxing

Une instance d’un type valeur nullable T? est boxée comme suit :

  • Si HasValue retourne false, la référence null est générée.
  • Si HasValue retourne true, la valeur correspondante du type valeur sous-jacent T est boxed, pas l’instance de Nullable<T>.

Vous pouvez effectuer l’unboxing du type valeur T vers le type T? correspondant, comme le montre l’exemple suivant :

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

Guide pratique pour identifier un type valeur nullable

L’exemple suivant montre comment déterminer si une instance System.Type représente un type valeur nullable construit, autrement dit, le type System.Nullable<T> avec un paramètre de type spécifié 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

Comme l’illustre l’exemple, vous utilisez l’opérateur typeof pour créer une instance System.Type.

Si vous souhaitez déterminer si une instance est d’un type valeur nullable, n’utilisez pas la méthode Object.GetType pour obtenir une instance Type à tester avec le code précédent. Quand vous appelez la méthode Object.GetType sur une instance d’un type valeur nullable, l’instance est boxed à Object. Comme le boxing d’une instance non nulle d’un type valeur nullable équivaut au boxing d’une valeur du type sous-jacent, GetType retourne une instance Type qui représente le type sous-jacent d’un type valeur nullable :

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

Par ailleurs, n’utilisez pas l’opérateur is pour déterminer si une instance est d’un type valeur nullable. Comme le montre l’exemple suivant, vous ne pouvez pas distinguer les types d’une instance et son instance de type sous-jacent à l’aide de l’opérateur is :

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?

Au lieu de cela, utilisez le Nullable.GetUnderlyingType du premier exemple et typeof pour vérifier si une instance est de type valeur nullable.

Notes

Les méthodes décrites dans cette section ne s’appliquent pas aux types de référence nullables.

spécification du langage C#

Pour plus d’informations, consultez les sections suivantes de la spécification du langage C# :

Voir aussi