Opérateurs C# null

Tip

Cet article fait partie de la section Notions de base pour les développeurs qui connaissent au moins un langage de programmation et apprennent C#. Si vous débutez avec la programmation, commencez par commencer par les didacticiels De prise en main . Pour obtenir la référence d’opérateur complète, consultez les opérateurs d’accès aux membres et les opérateurs de coalescence de null dans la référence du langage.

C# fournit plusieurs opérateurs qui rendent le code null-safe concis. Au lieu d'imbriquer if (x != null) des gardes tout au long de votre code, ces opérateurs vous permettent d’exprimer un accès sécurisé face à null, des valeurs alternatives et des tests de nullité dans une seule expression.

Cet article traite de ?. et ?[] pour l’accès conditionnel null, de ?? pour l'opérateur de coalescence de null, de ??= pour l’affectation de coalescence de null et de is null/is not null pour la correspondance de modèle null.

Accès au membre conditionnel Null ?.

L’opérateur ?. accède à un membre uniquement lorsque l’objet n’est pas null. Lorsque l’objet est null, l’expression entière prend la valeur de null au lieu de lever un NullReferenceException.

string? name = null;

// Without ?., accessing a member on null throws NullReferenceException:
// int len = name.Length; // throws if name is null

// ?. returns null instead of throwing:
int? len = name?.Length;
Console.WriteLine(len.HasValue); // False

name = "C#";
Console.WriteLine(name?.Length); // 2

L'opérateur ?. effectue un court-circuit : lorsque l'expression du côté gauche est null, tout ce qui est à droite est ignoré. Aucun appel de méthode n’est exécuté et aucun effet secondaire ne se produit.

Vous pouvez chaîner plusieurs ?. opérateurs dans une seule expression. La chaîne s’arrête au premier null qu’elle rencontre :

string? input = null;

// Chain ?. across multiple method calls — short-circuits at the first null:
string? upper = input?.Trim()?.ToUpperInvariant();
Console.WriteLine(upper ?? "(none)"); // (none)

input = "  hello  ";
Console.WriteLine(input?.Trim()?.ToUpperInvariant()); // HELLO

Accès à l’indexeur conditionnel Null ?[]

L’opérateur ?[] applique le même comportement de court-circuit à l’indexeur et à l’accès au tableau. Utilisez-la lorsque la collection elle-même peut être null:

string[]? tags = null;

// ?[] accesses an element only when the collection is non-null
string? first = tags?[0];
Console.WriteLine(first ?? "(none)"); // (none)

tags = ["csharp", "dotnet", "nullable"];
Console.WriteLine(tags?[0]);          // csharp

Chaîner les opérateurs conditionnels nulls

Chaînez plusieurs ?. opérateurs afin d'accéder à un chemin de références potentiellement nulles. La chaîne se court-circuite au premier null :

var order = new Order("ORD-001", null);

// Each ?. short-circuits when null: Customer is null, so Address and City are never accessed
string? city = order.Customer?.Address?.City;
Console.WriteLine(city ?? "(no city)"); // (no city)

var fullOrder = new Order("ORD-002",
    new Customer("Alice", new Address("123 Main St", "Springfield", "IL")));

Console.WriteLine(fullOrder.Customer?.Address?.City); // Springfield

Quand Customer est null, ni Address ni City ne sont évalués. L’expression entière renvoie null.

Appel de délégué thread-safe

?. fournit un moyen propre et thread-safe d’appeler un délégué ou de déclencher un événement. L’expression de délégué n’est évaluée qu’une seule fois. Par conséquent, il n’existe aucune fenêtre pour qu’un autre thread se désabonne entre la vérification null et l’appel :

EventHandler? clicked = null;

// No subscribers — ?.Invoke does nothing instead of throwing NullReferenceException
clicked?.Invoke(null, EventArgs.Empty);

clicked += (_, _) => Console.WriteLine("Button clicked!");

// With a subscriber — ?.Invoke calls the handler
clicked?.Invoke(null, EventArgs.Empty);
// Output: Button clicked!

Ce modèle remplace l’idiome plus ancien if (clicked != null) clicked(...) .

Fusion de Null??

L’opérateur ?? retourne son opérande de gauche lorsqu’il n’est pas nul, et son opérande de droite lorsque celui de gauche est null. Utilisez-la pour fournir une valeur par défaut :

string? username = null;

// ?? returns the right-hand value when the left-hand is null
string display = username ?? "Guest";
Console.WriteLine(display); // Guest

username = "alice";
display  = username ?? "Guest";
Console.WriteLine(display); // alice

?? est associatif de droite, donc a ?? b ?? c évalue comme a ?? (b ?? c). La première valeur non null gagne. Un modèle courant consiste à chaîner ?. avec ?? : utiliser ?. pour parcourir en toute sécurité une chaîne potentiellement nulle, puis ?? pour substituer une valeur par défaut si la chaîne retourne null. Pour obtenir un exemple complet, consultez Combiner des opérateurs Null.

Attribution de fusion Null ??=

L’opérateur ??= affecte la valeur de droite à une variable uniquement lorsque la variable est null. Utilisez-la pour l’initialisation différée :

List<string>? cache = null;

// ??= assigns only when the variable is null
cache ??= LoadData();
Console.WriteLine(cache.Count); // 3

// cache is already non-null, so LoadData() isn't called again
cache ??= LoadData();
Console.WriteLine(cache.Count); // 3

static List<string> LoadData() => ["alpha", "beta", "gamma"];

L’expression de droite est évaluée uniquement lorsque la variable est null. Lorsque la variable a déjà une valeur, le côté droit n’est pas évalué du tout.

Affectation conditionnelle nulle (C# 14)

À compter de C# 14, vous pouvez utiliser ?. et ?[] comme cibles d’affectation. L’affectation s’exécute uniquement lorsque l’objet de gauche n’est pas null :

AppConfig? config = new AppConfig();

// Assigns only when config is non-null (C# 14)
config?.Theme = "dark";
Console.WriteLine(config?.Theme); // dark

AppConfig? missing = null;
missing?.Theme = "light";                         // no-op: missing is null
Console.WriteLine(missing?.Theme ?? "(no config)"); // (no config)

Le côté droit est évalué uniquement lorsque le côté gauche est connu comme non nul.

Correspondance de modèle Null : is null et is not null

Les modèles is null et is not null testent si une expression est null:

string? input = null;

// is null is the preferred test — unaffected by operator overloading
if (input is null)
{
    Console.WriteLine("No input provided.");
}

// == null also works, but a custom == operator can change its behavior
if (input == null)
{
    Console.WriteLine("Still no input.");
}

Préférez is null à == null pour les vérifications de nullité. L’opérateur == peut être surchargé, ce qui signifie que x == null peut retourner true même lorsque x n'est pas null si le type définit un opérateur d’égalité personnalisé. Le is null modèle teste toujours la référence null réelle, quelle que soit la surcharge de l’opérateur.

string? value = "hello";

if (value is not null)
{
    Console.WriteLine(value.ToUpper()); // HELLO
}

Combiner des opérateurs null

En pratique, vous combinez souvent plusieurs de ces opérateurs. Une expression peut parcourir en toute sécurité un graphe d'objet profond, appliquer une valeur par défaut, puis effectuer une vérification sur le résultat :

Order? order = GetPendingOrder();

// Chain ?. for safe traversal, ?? for a fallback, is null for a clear guard
string city = order?.Customer?.Address?.City ?? "unknown";

if (order is null)
{
    Console.WriteLine("No pending order.");
}
else
{
    Console.WriteLine($"Shipping to: {city}");
}
// Output: No pending order.

Opérateur Null-forgiving !

L’opérateur ! postfix supprime les avertissements nullables. Ajoutez ! pour indiquer au compilateur « cette expression n’est certainement pas null ». L’opérateur n’a aucun effet au moment de l’exécution. Elle affecte uniquement l’analyse de l’état null du compilateur.

string? name = FindUser("alice");

// Use ! only when you have information the compiler doesn't.
// FindUser guarantees a non-null result for known usernames.
int length = name!.Length;
Console.WriteLine(length); // 5

Utilisez ! avec parcimonie, et uniquement lorsque vous avez des informations que le compilateur ne contient pas. Les exemples incluent des tests qui passent intentionnellement null pour valider la logique de vérification des arguments ou appeler une méthode dont le contrat garantit un retour non nul pour une entrée connue. La surutilisation ! élimine l’objectif des types de référence nullables. Pour obtenir une explication complète, consultez les types de référence Nullable.

Voir aussi