1. Le problème NullReferenceException
Presque chaque débutant (et pas que) en C# est déjà tombé au moins une fois sur ce message flippant :
System.NullReferenceException: Référence d’objet non définie à une instance d’un objet.
Voilà un classique du genre :
string hello = null;
Console.WriteLine(hello.Length); // BAM ! NullReferenceException
Le principe est simple : tu essaies d’accéder à un objet qui n’existe pas. Genre, la variable pointe sur null — un trou à la place d’un objet.
Pourquoi c’est facile de se planter ?
Parce que la plupart des types de référence en C# pouvaient historiquement prendre la valeur null. Les devs oubliaient souvent de vérifier si la variable pointait vraiment sur un objet, et du coup, ils se prenaient le fameux NullReferenceException.
Si un dev touchait un dollar à chaque NullReferenceException, il aurait déjà codé son propre OS.
Pourquoi c’est un souci ?
Avant, on a appris à faire en sorte que des valeurs comme int? ou double? puissent être null — pour les cas où on veut dire explicitement "pas de valeur" (genre un champ vide dans une base de données).
Mais les types de référence (genre string, n’importe quelle classe, tableaux, etc.) pouvaient toujours être null. C’est comme ça depuis la naissance de C#. Pratique, mais risqué — parce que le langage ne t’obligeait pas à te demander : "Et si ce pointeur est vide ?"
2. Évolution : Nullable Reference Types (NRT)
Il y a 5 ans, une nouveauté a débarqué et a tout retourné dans la lutte contre les NullReferenceException — les Nullable Reference Types (NRT).
string s = "hello"; // référence non-nullable
string? maybe = null; // référence nullable
L’idée principale :
- Séparer clairement les variables de référence qui ne peuvent pas être null de celles qui peuvent l’être.
- Aider le dev à voir les soucis potentiels avec null dès la compilation, pas en runtime (quand il est trop tard).
Dans les nouvelles versions de C#, la façon de déclarer les variables de référence a changé : par défaut, tu ne peux pas mettre null, sauf si tu l’as explicitement autorisé.
Juste un petit ? — et le sens de la variable change direct !
3. Activer les Nullable Reference Types
Par défaut, cette syntaxe stricte est désactivée dans la plupart des projets, pour ne pas casser l’ancien code. Mais les templates modernes dans Visual Studio, Rider et .NET CLI créent déjà des projets avec les NRT activés — ou au moins te le conseillent fort.
Pour savoir si les NRT sont activés dans ton projet, cherche cette ligne dans le fichier .csproj :
<Nullable>enable</Nullable>
Si tu ne la trouves pas, tu peux l’ajouter à la main — c’est safe.
Qu’est-ce que ça change dans le code ?
- Si les NRT sont désactivés (ancien comportement) : string s = null; — pas d’erreur, tout le monde s’en fout.
- Si activés : le compilateur va râler si tu essaies de mettre null là où il ne faut pas.
4. Exemples avec NRT
Exemple simple
#nullable enable // Cette ligne active la vérification NRT pour ce fichier
string notNullable = "Salut";
string notNullable2 = null; // ERREUR de compilation !
string? nullableString = null; // Tout va bien, on a explicitement autorisé null
Dans la première ligne, on déclare une string qui doit toujours pointer sur un vrai objet.
Dans la troisième — une string qui peut être null.
Vérification de null
void PrintLength(string? s)
{
// Le compilateur va râler : "Et si s == null ?"
Console.WriteLine(s.Length);
// Comme ça, c’est bon
if (s != null)
{
Console.WriteLine(s.Length);
}
}
Le compilateur t’aide maintenant à ne pas oublier les checks !
Avertissements du compilateur
Si tu ignores l’avertissement et que tu accèdes quand même à une variable nullable sans vérifier — tu auras un nouvel avertissement (super utile !) du compilateur. Ce n’est pas une erreur (le programme compile quand même), mais la petite "ampoule" jaune te dit : "T’es sûr, poto ?"
Comparons les modes :
| Type C# | Peut être null ? | Mode Legacy (avant NRT) | Mode NRT (#nullable enable) |
|---|---|---|---|
| int | Non | Non | Non |
| int? | Oui | Oui | Oui |
| string | Oui | Non (toujours possible) | Non (par défaut interdit) |
| string? | Oui | Non | Oui |
5. Conseils : pourquoi et comment utiliser les NRT
- Moins de bugs : Moins de crashs surprises à cause de null, plus de bonheur pour le dev et l’utilisateur.
- Code plus clair : On voit direct ce qui peut être vide et ce qui doit toujours être rempli.
- Aide du compilateur : Faut l’avouer — il bosse vraiment pour nous ! Les warnings NRT sont une vraie mine d’infos sur les bugs potentiels.
Où c’est indispensable
- Dans les gros projets où plein de gens bossent sur le même code.
- Dans les API et libs publiques — pour expliquer aux autres ce qu’ils peuvent ou pas faire.
- Là où la fiabilité est critique (genre applis bancaires, systèmes médicaux, etc.)
6. Erreurs classiques et pièges
- "T’as oublié le ?"
Tu mets null dans une string normale (string s = null;) — et le compilateur râle, parce que maintenant, par défaut, une string normale ne doit pas être null. - "T’as mis des ? partout"
Tu mets toutes tes variables en string? juste pour que le compilateur te laisse tranquille. Mais le but, c’est d’annoter précisément là où la valeur vide est vraiment possible. - "T’as mal compris le warning"
Tu ignores l’avertissement, et tu te prends un NullReferenceException là où tu croyais que le compilateur te couvrait.
GO TO FULL VERSION