Aller au contenu principal

Propriétés et accesseurs

Notions théoriques

Propriétés auto-implémentées

La syntaxe la plus courante en C# utilise les propriétés auto-implémentées : le compilateur génère automatiquement le champ de stockage.

class Etudiant
{
public string Nom { get; set; } = ""; // lecture + écriture publiques
public double Note { get; private set; } // lecture publique, écriture privée
public int Id { get; } // lecture seule (set uniquement dans le constructeur)
}

Propriétés avec corps (get/set explicites)

Quand on a besoin de validation ou de logique, on écrit les accesseurs get et set explicitement :

class Produit
{
private decimal _prix;

public decimal Prix
{
get => _prix;
set
{
if (value < 0)
throw new ArgumentOutOfRangeException(nameof(value), "Prix négatif interdit.");
_prix = value;
}
}
}

var p = new Produit();
p.Prix = 49.99m; // OK
// p.Prix = -5m; // ArgumentOutOfRangeException !
Le mot-clé value

Dans le set, value représente la valeur assignée par l'appelant : p.Prix = 49.99mvalue vaut 49.99m. C'est une variable implicite disponible uniquement dans les accesseurs set.

Propriétés calculées — get uniquement

Une propriété peut calculer sa valeur à partir d'autres propriétés, sans stocker de données supplémentaires :

class Rectangle
{
public double Largeur { get; set; }
public double Hauteur { get; set; }

public double Aire => Largeur * Hauteur; // calculée
public double Perimetre => 2 * (Largeur + Hauteur);
}

var r = new Rectangle { Largeur = 4, Hauteur = 3 };
Console.WriteLine(r.Aire); // 12
Console.WriteLine(r.Perimetre); // 14

init — propriété initialisable seulement à la création (C# 9+)

init remplace set pour les propriétés qu'on veut pouvoir définir lors de l'initialisation de l'objet mais pas modifier ensuite :

class Personne
{
public string Prenom { get; init; } = "";
public string Nom { get; init; } = "";
public string NomComplet => $"{Prenom} {Nom}";
}

var p = new Personne { Prenom = "Alice", Nom = "Martin" };
// p.Prenom = "Bob"; // ERREUR — init seulement !
Console.WriteLine(p.NomComplet); // "Alice Martin"

private set vs init

private setinit
Modifiable depuis la classeOuiNon
Modifiable lors de l'init { }NonOui
Utilisation typiqueÉtat interne géré par la classeObjet immuable après création

Propriété avec validation complète

class Etudiant
{
private string _nom = "";
private double _note;

public string Nom
{
get => _nom;
set => _nom = string.IsNullOrWhiteSpace(value)
? throw new ArgumentException("Le nom ne peut pas être vide.")
: value.Trim();
}

public double Note
{
get => _note;
set => _note = value is >= 0 and <= 20
? value
: throw new ArgumentOutOfRangeException(nameof(value), "Note invalide (0-20).");
}

public string Mention => Note switch
{
>= 16 => "Très bien",
>= 14 => "Bien",
>= 12 => "Assez bien",
>= 10 => "Passable",
_ => "Insuffisant",
};
}

Exemple pratique

class Temperature
{
private double _celsius;

public double Celsius
{
get => _celsius;
set
{
if (value < -273.15)
throw new ArgumentOutOfRangeException(nameof(value),
"En dessous du zéro absolu (-273.15°C) : impossible.");
_celsius = value;
}
}

public double Fahrenheit
{
get => _celsius * 9 / 5 + 32;
set => Celsius = (value - 32) * 5 / 9;
}

public double Kelvin
{
get => _celsius + 273.15;
set => Celsius = value - 273.15;
}

public string Description => _celsius switch
{
< 0 => "En dessous de 0°C",
< 15 => "Froid",
< 25 => "Tempéré",
< 35 => "Chaud",
_ => "Très chaud",
};

public override string ToString()
=> $"{Celsius:F1}°C / {Fahrenheit:F1}°F / {Kelvin:F1}K — {Description}";
}

var t = new Temperature { Celsius = 20 };
Console.WriteLine(t);

t.Fahrenheit = 98.6;
Console.WriteLine(t);

Test de mémorisation/compréhension


Que représente `value` dans un accesseur `set` ?


Quelle déclaration crée une propriété modifiable uniquement à l'initialisation ?


Qu'est-ce qu'une propriété calculée ?


Quelle est la différence entre `private set` et `init` ?


Quelle syntaxe crée une propriété en lecture seule pure (aucune modification possible) ?


TP pour réfléchir et résoudre des problèmes

Vous allez créer une classe Panier avec des propriétés soigneusement conçues.

Étape 1 — Propriété avec validation


Bonne pratique - Valider dans le setter, pas dans le getter

Validez les données dans le set, jamais dans le get. Le get doit simplement retourner la valeur actuelle. Le set est le point d'entrée où on s'assure que la classe ne peut jamais se retrouver dans un état invalide.

Étape 2 — Propriétés calculées


Bonne pratique - Les propriétés calculées sont toujours à jour

Contrairement à un champ mis à jour manuellement, une propriété calculée est recalculée à chaque accès. TotalTTC sera toujours cohérent avec les articles et la remise actuels — impossible d'oublier de "recalculer le total" après une modification.

Étape 3 — Affichage de la facture


Bonne pratique - La logique métier dans la classe, pas dans Program.cs

Toute la logique de calcul (TVA, remise) est dans la classe Panier. Program.cs se contente d'appeler les propriétés et d'afficher. Si la TVA passe de 20% à 21%, vous modifiez un seul endroit dans la classe.

📌 Une solution