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 !
valueDans le set, value représente la valeur assignée par l'appelant : p.Prix = 49.99m → value 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 set | init | |
|---|---|---|
| Modifiable depuis la classe | Oui | Non |
Modifiable lors de l'init { } | Non | Oui |
| Utilisation typique | État interne géré par la classe | Objet 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
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
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
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
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.