Lors de la création d’un type d’une librairie, qu’il soit une  class, une struct, ou un record, il est d’usage d’indiquer à l’utilisateur de ce type que l’initialisation d’une de ses propriétés est requise.

Cela permet d’éviter d’avoir une référence null, et donc de causer une erreur lors de l’exécution du programme.

Comment on faisait avant ? 🤔

Auparavant, il suffisait de marquer comme nullable une propriété.

Si elle n’était pas nullable (et ce en activant les nullable reference types), on déduisait qu’il fallait lui donner une valeur, ce sans quoi cette dernière était celle par défaut.

Prenons ici l’exemple d’une librairie qui contient un type Insider:public record Insider 
{
// ici, on tire parti des nullable value types pour indiquer qu'une valeur est optionnelle
   public int? Age { get; set; }
// idem ici, avec les nullable reference types.
   public string Nom { get; set; }
   public string? FilmPréféré { get; set; }
// Ici, on indique tacitement à l'utilisateur du type que la variable doit être initialisée, sinon elle aura une valeur par défaut
   public bool EstEnMission { get; set; }
}

Bon, ça, on connaît. Mais effectivement, comme marqué dans le commentaire du code ci-dessus, ce sont des moyens tacites d’indiquer le caractère requis d’une propriété.

En effet, si l’utilisateur, lors du new du type Insider, ne donne pas de valeur à ces variables, il se passe ceci: au mieux, l’utilisateur a un warning. Et au pire, rien n’est indiqué du tout.

Sans erreur de compilation, l’utilisateur de cette librairie est finalement en roue libre jusqu’à ce que son programme ne se comporte pas exactement comme il le pensait. Tout cela parce qu’il n’a pas mis la valeur requise dans cette satanée variable, ou bien qu’elle était null, et que le code n’était pas assez explicite pour dire quelle était la valeur requise de premier abord.

Les constructeurs existent… non ? ⚒️

Alors oui, il est possible d’utiliser un constructeur public avec des paramètres, pour forcer l’initialisation d’une variable. Mais écrire un ou plusieurs constructeurs, c’est souvent de la duplication de code.

Voire pire, dans le cas d’une class/record qui hérite d’une autre, on arrive souvent à du code boilerplate.

Voyez par vous-même:

record Person(string FirstName, string LastName, string MiddleName = "");
record Student(int ID, string FirstName, string LastName, string MiddleName = "") : Person(FirstName, LastName, MiddleName);

Ici, même si elle est minimaliste, la duplication est présente. Et cette duplication peut se multiplier si la codebase grandit. Si l’on veut changer un paramètre de ce constructeur, il va falloir retourner dans tous les endroits du code qui font appel à ce même constructeur pour adapter ce changement.

Chez Code Insider, le boilerplate et la duplication, on aime pas trop ça.

La solution de C#11: Le mot-clef required 😏

Il y aurait pourtant un meilleur moyen de pallier au problème.

Transformer les warning des nullable reference-type en message d’erreur ? → Trop breaking-change pour le moment.

Faire en sorte que les développeurs lisent enfin la doc ? → Impossible.

Les propriétés sont elles ainsi vouées à rester optionnelles, comme elles le sont depuis la première version de C# ? Non.

En fait, vous l’avez lu: C#11 introduit un nouveau mot-clef contextuelrequired. Ce dernier permet d’indiquer qu’il est absolument indispensable d’initialiser une propriété pour pouvoir new un type.

namespace Dotnet7;
public record Insider
{
    public required int Age { get; set; }
}

Avec ce bout de code, il y aura l’erreur de compilation suivante qui s’affichera si l’on fait un new sans initialiser la propriété:

Required member ‘Insider.Age‘ must be set in the object initializer or attribute constructor.

Pour fixer cela, il faut donc initialiser la propriété, ainsi:

On évite ainsi d’oublier d’initialiser une valeur cruciale, parce que l’auteur du type nous indique qu’il est requis d’initialiser cette propriété.

C#11 est disponible avec .NET 7, qui est actuellement en RC2 à l’heure où nous écrivons ces lignes. Vivement qu’il sorte ! ✌️

Conclusion 😊

Je pense sincèrement que le mot-clef required aura une place centrale dans nos développements .NET, et ce dans les années à venir.

Il permettra de donner plus de pouvoir aux auteurs de librairies sur les valeurs qui sont absolument requises pour fabriquer une instance d’un type.

Également, cela permettrait ainsi, à terme, de réduire le nombre de NullReferenceException, et donc nous permettre de sauver quelques milliards de dollars 😎.