Classes et objets
Notions théoriques
Anatomie d'une classe C#
Une classe regroupe des champs (données internes), des propriétés (accès contrôlé aux données) et des méthodes (comportements).
class Etudiant
{
// Champ privé — préfixe _ par convention
private double _note;
// Propriétés publiques (accès contrôlé)
public string Nom { get; set; } = "";
public int Age { get; set; }
public double Note
{
get => _note;
set => _note = (value >= 0 && value <= 20) ? value : _note; // validation
}
// Méthode publique — comportement
public string ObtenirMention() => Note switch
{
>= 16 => "Très bien",
>= 14 => "Bien",
>= 12 => "Assez bien",
>= 10 => "Passable",
_ => "Insuffisant",
};
// Surcharge de ToString() pour l'affichage
public override string ToString()
=> $"Etudiant({Nom}, {Age} ans, {Note:F1}/20)";
}
Champs privés — convention _underscore
En C#, les champs privés utilisent conventionnellement un préfixe _ (underscore) pour les distinguer des paramètres et propriétés :
class Compte
{
private decimal _solde; // champ privé : _solde
private string _titulaire; // champ privé : _titulaire
public decimal Solde => _solde; // propriété en lecture seule
public string Titulaire => _titulaire;
public void Deposer(decimal montant)
{
if (montant <= 0)
throw new ArgumentException("Le montant doit être positif.");
_solde += montant;
}
}
Membres statiques — partagés par toutes les instances
Un membre statique appartient à la classe, pas à un objet particulier. Toutes les instances partagent la même valeur.
class Etudiant
{
// Champ statique — partagé par tous les étudiants
private static int _nombreTotal = 0;
public string Nom { get; set; } = "";
public Etudiant(string nom)
{
Nom = nom;
_nombreTotal++; // incrémenté à chaque création
}
// Propriété statique — accessible sans instance
public static int NombreTotal => _nombreTotal;
}
var a = new Etudiant("Alice");
var b = new Etudiant("Bob");
Console.WriteLine(Etudiant.NombreTotal); // 2 — on accède via le nom de la classe
Surcharger ToString()
ToString() est appelée automatiquement lors d'un affichage (Console.WriteLine(obj) ou interpolation $"{obj}"). On la surcharge avec override :
class Produit
{
public string Nom { get; set; } = "";
public decimal Prix { get; set; }
public override string ToString()
=> $"{Nom} ({Prix:F2} €)";
}
var p = new Produit { Nom = "Clavier", Prix = 49.99m };
Console.WriteLine(p); // "Clavier (49.99 €)"
Console.WriteLine($"Produit : {p}"); // "Produit : Clavier (49.99 €)"
Classe statique — utilitaires purs
Une classe statique ne peut pas être instanciée. Elle ne contient que des méthodes statiques (utilitaires).
static class Calculateur
{
public static double Moyenne(double[] notes)
=> notes.Length == 0 ? 0 : notes.Average();
public static string Mention(double note) => note switch
{
>= 16 => "Très bien",
>= 10 => "Passable",
_ => "Insuffisant",
};
}
double moy = Calculateur.Moyenne([15.5, 12.0, 9.5]);
Console.WriteLine(Calculateur.Mention(moy));
Exemple pratique
class Produit
{
private static int _prochainId = 1;
public int Id { get; }
public string Nom { get; set; } = "";
public decimal Prix { get; set; }
public int Stock { get; private set; }
public static int NombreProduits => _prochainId - 1;
public Produit(string nom, decimal prix, int stockInitial)
{
Id = _prochainId++;
Nom = nom;
Prix = prix;
Stock = stockInitial;
}
public bool Vendre(int quantite)
{
if (quantite <= 0 || quantite > Stock)
return false;
Stock -= quantite;
return true;
}
public void Reapprovisionner(int quantite)
{
if (quantite > 0)
Stock += quantite;
}
public override string ToString()
=> $"[{Id:D3}] {Nom,-20} {Prix,8:F2} € | Stock : {Stock,4}";
}
// Utilisation
var produits = new List<Produit>
{
new Produit("Clavier mécanique", 69.99m, 5),
new Produit("Souris ergonomique", 49.99m, 0),
new Produit("Câble USB-C", 9.99m, 12),
};
Console.WriteLine("=== Catalogue ===");
foreach (var p in produits)
Console.WriteLine(p);
Console.WriteLine($"\nNombre de produits : {Produit.NombreProduits}");
// Opérations
produits[0].Vendre(2);
produits[1].Reapprovisionner(10);
Console.WriteLine("\n=== Après opérations ===");
foreach (var p in produits)
Console.WriteLine(p);
Test de mémorisation/compréhension
TP pour réfléchir et résoudre des problèmes
Vous allez créer une classe CompteBancaire avec des membres privés et statiques.
Étape 1 — Définir la classe avec un compteur statique
Créez la classe avec un identifiant auto-incrémenté.
Le champ _solde est privé : personne ne peut le modifier directement de l'extérieur. On expose la valeur en lecture seule via public decimal Solde => _solde. Pour modifier le solde, il faut passer par les méthodes Deposer et Retirer qui peuvent appliquer des règles métier (ex: refuser un montant négatif).
Étape 2 — Ajouter les méthodes Deposer et Retirer
Implémentez les opérations bancaires avec validation.
Retirer retourne bool plutôt que de lever une exception, car un solde insuffisant est une situation normale (pas une erreur de programmation). L'appelant peut tester le résultat : if (!compte.Retirer(500m)) Console.WriteLine("Solde insuffisant.");. Les exceptions sont réservées aux erreurs vraiment inattendues.
Étape 3 — Surcharger ToString et tester
Ajoutez ToString() et créez plusieurs comptes pour tester.
Une bonne implémentation de ToString() rend le débogage beaucoup plus facile. Quand vous mettez un point d'arrêt dans un IDE (Visual Studio, Rider), la valeur affichée dans l'inspecteur de variables est celle de ToString(). Un affichage comme "Compte #0001 | Alice Martin | Solde : 1250.00 €" est immédiatement lisible.