CodeGym /Cours /C# SELF /required propriétés et propriétés field

required propriétés et propriétés field

C# SELF
Niveau 17, Leçon 3
Disponible

1. Introduction

Programmer en C# sans propriétés, c'est possible, mais c'est un peu comme faire du roller à la Maison Blanche — possible, mais franchement pas confortable. Non seulement on s'est habitué à la syntaxe courte sans les getters et setters inutiles, mais dès que notre appli commence à manipuler des modèles «sérieux» (genre une classe User qui décrit un utilisateur dans le système), ça devient super important de garantir que toutes les données nécessaires sont bien là.

Par exemple, si on a une classe :

public class User
{
    public string Name { get; set; }
    public int Age { get; set; }
}

On peut facilement oublier d'initialiser les propriétés :

User user = new User(); // Name sera null, Age = 0

Résultat : dix écrans plus loin et après cent détours logiques, tu te prends le fameux NullReferenceException et tu vas galérer à trouver le coupable.

Petit rappel sur les propriétés init-only

Ouais, on peut utiliser l'initialisation seulement à la création :

public string Name { get; init; }

Mais même avec cette syntaxe, personne ne force l'utilisateur de la classe à passer une valeur s'il n'en a pas envie — la plupart des constructeurs par défaut initialisent les champs avec les valeurs par défaut (null, 0, etc.).

Alors comment obliger le dev (ou toi-même !) à ne pas oublier de mettre la bonne valeur ? C'est justement pour ça qu'on a inventé le modificateur required, apparu dans C# 11.

2. Propriétés required : initialisation stricte

Le modificateur required — c'est une indication au compilateur pour qu'il vérifie qu'une propriété d'un objet est explicitement définie au moment de sa création. En gros, si cette propriété n'est pas initialisée à la création de l'objet — le compilateur te bloque, et l'IDE te met une grosse vague rouge flippante.


public class User
{
    public required string Name { get; set; }
    public int Age { get; set; }
}
Propriété obligatoire avec required

Essayons de créer un utilisateur :

// Erreur de compilation : la propriété Name doit être initialisée !
User user1 = new User();

Ou comme ça :


// Erreur de compilation : propriété required Name non renseignée
User user2 = new User { Age = 18 };

Et voici la bonne façon :

User user3 = new User { Name = "Hermione", Age = 18 };

Comment fonctionne required ?

Le modificateur required dit au compilateur : «Après l'exécution du constructeur de l'objet (n'importe lequel !), cette propriété doit être explicitement définie».

Ça marche aussi bien pour les propriétés classiques que pour les init-only :

public required string Name { get; init; }

Si tu déclares un constructeur custom qui initialise la propriété required, c'est bon aussi.

Schéma classique de vérification

Scénario Le compilateur est content ?
Propriété required non renseignée ❌
Renseignée dans l'initialiseur d'objet ✔️
Renseignée dans le constructeur ✔️

Exemple dans notre modèle «Chien»

public class Dog
{
    public required string Name { get; set; }
    public int Age { get; set; }
}

Dog dog = new Dog { Name = "Fido", Age = 5 }; // Tout est ok !
Dog badDog = new Dog { Age = 2 }; // Erreur ! Name non renseigné

Où required est vraiment utile ?

  • Transfert de DTO entre couches : Si tu as une API, il faut que tous les champs nécessaires arrivent à l'entrée.
  • Modèles complexes avec attributs obligatoires : Par exemple, Product avec un SKU obligatoire, Order avec un numéro obligatoire.
  • En entretien ou en code review : Si tu montres cette syntaxe, ton code sera lu avec respect (et un peu de jalousie).

3. Comment required marche avec les constructeurs ?

Parfois tu écris explicitement un constructeur. Que se passe-t-il si tu n'initialises pas la propriété required dans le constructeur ou l'initialiseur d'objet ? Le compilateur va râler.


public class Article
{
    public required string Title { get; set; }
    public required string Author { get; set; }

    public Article()
    {
        // Si tu n'initialises pas Title et Author — erreur de compilation !
        // Tu peux faire comme ça :
        Title = "Sans titre";
        Author = "Inconnu";
    }
}

Si le constructeur assigne lui-même les valeurs des propriétés required — tout roule. Sinon, tu dois initialiser ces champs via l'initialiseur d'objet (new Article { ... }).

Spécificités d'utilisation

  • required ne marche que sur les propriétés, pas sur les champs.
  • required n'est pas hérité — si la propriété de base est required, mais que tu ne mets pas required dans la classe dérivée, le compilateur ne dit rien (mais c'est mieux de le remettre explicitement dans la classe dérivée).
  • required ne peut pas être appliqué aux champs automatiques ou à autre chose qu'une property.

4. Syntaxe fléchée pour les propriétés

Avec les nouvelles versions de C#, on cherche de plus en plus à écrire du code concis et expressif. Une des nouveautés les plus cool pour les propriétés — c'est la syntaxe fléchée (ou expression-bodied properties).

Parfois, tu veux juste définir une propriété qui retourne une valeur sans logique supplémentaire. Avant, il fallait écrire tout le getter avec des accolades :

public int Age
{
    get { return birthYear > 0 ? DateTime.Now.Year - birthYear : 0; }
}

Maintenant, tu peux écrire beaucoup plus court — avec la flèche (=>) :


public int Age => birthYear > 0 ? DateTime.Now.Year - birthYear : 0;

Cette syntaxe s'appelle propriété à corps d'expression (expression-bodied property). C'est parfait pour les calculs simples et ça rend le code plus compact.

Exemple d'utilisation de get et set

public class Book
{
    private string _title;

    public string Title
    {
        get => _title;
        set => _title = value.Trim();
    }
}

Ici, get retourne la valeur du champ, et set — assigne la valeur après avoir supprimé les espaces inutiles au début et à la fin.

Exemple d'utilisation de get seul (lecture seule) :

Si la propriété est en lecture seule — tu peux l'écrire sans accolades, juste avec =>.

public class Person
{
    private string name = "Mark Twain";

    // Lecture seule : propriété calculée
    public string Name => name.ToUpper();
}

Ici, la propriété Name est accessible seulement en lecture — elle retourne toujours name en majuscules.

5. Mot-clé field pour les propriétés

Avant C# 14, si tu voulais accéder au champ caché d'une propriété auto-implémentée directement dans le setter ou le getter (genre pour éviter la récursion ou ajouter ta logique) — c'était impossible. Il fallait déclarer le champ explicitement.

C# 14 permet d'accéder au champ caché d'une propriété auto-implémentée avec le mot-clé field :


public class Person
{
    public string Name
    {
        get => field; // field — c'est le champ caché de la propriété Name
        set
        {
            if (string.IsNullOrWhiteSpace(value))
                throw new ArgumentException("Le nom ne peut pas être vide !");
            field = value; // on utilise field au lieu d'un _name explicite
        }
    }
}

Avant, il fallait faire comme ça :

private string _name;
public string Name
{
    get => _name;
    set
    {
        if (string.IsNullOrWhiteSpace(value))
            throw new ArgumentException("Le nom ne peut pas être vide !");
        _name = value;
    }
}

Ça fait une variable de moins à déclarer. Plus le code est compact, mieux c'est.

Pourquoi c'est parfois important d'accéder au champ dans la propriété ?

  • Parfois tu veux contrôler où et comment la valeur est stockée (genre si tu veux retourner une copie, mettre en cache le résultat ou faire du lazy-loading).
  • Si tu veux utiliser des attributs ou du reflection — le champ peut être utile par son nom.
  • Dans certains cas de (dé)sérialisation ou d'optimisation des perfs, tu veux avoir plus de contrôle sur le stockage de la valeur.

Exemples d'utilisation :

Validation des données dans le setter

public double Grade
{
    get => field;
    set
    {
        if (value < 0 || value > 5)
            throw new ArgumentOutOfRangeException("La note doit être entre 0 et 5");
        field = value;
    }
}

Statistiques sur les changements de valeur

public int StepCount
{
    get => field;
    set
    {
        if (value > field)
        {
            Console.WriteLine($"Yes ! Tu as fait {value - field} pas de plus !");
        }
        field = value;
    }
}

Lazy Load

public string Data
{
    get
    {
        if (field == null)
            field = LoadDataFromDatabase();
        return field;
    }
    set => field = value;
}

6. Erreurs classiques et subtilités

Erreur n°1 : oublier d'initialiser une propriété required.
Le compilateur ne te laissera pas passer et te sortira une erreur direct à la compilation, ce qui évite les galères à l'exécution.

Erreur n°2 : les propriétés required ne marchent pas sans initialisation complète dans le constructeur.
Si le constructeur ne prend pas de valeurs pour toutes les propriétés obligatoires, le compilateur te rappellera que t'as oublié un truc.

Erreur n°3 : essayer d'utiliser required avec const ou readonly.
Ces modificateurs sont incompatibles — required ne s'applique qu'aux propriétés classiques. Essayer de les combiner, c'est l'erreur assurée.

2
Mission
C# SELF, niveau 17, leçon 3
Bloqué
Création d'une classe avec des propriétés required
Création d'une classe avec des propriétés required
2
Mission
C# SELF, niveau 17, leçon 3
Bloqué
Logique personnalisée dans les getters et setters avec field
Logique personnalisée dans les getters et setters avec field
Commentaires
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION