DTeK Learn logo

Les Classes en C#

29/09/2023

Les classes jouent un rôle central dans la programmation orientée objet (POO) en C#. Elles permettent d’organiser et de structurer efficacement le code, favorisant la réutilisation et la maintenance du logiciel. Explorerons en détail les classes en C# et leur utilisation. Que tu sois un développeur en reconversion professionnelle ou un développeur junior, ce guide complet t’aidera à maîtriser cet aspect fondamental de la POO.

jeune développeur en reconversion professionnelle sur son ordinateur à son bureau

1. Qu’est-ce qu’une Classe en C# ?

Une classe en C# est un concept fondamental. Elle permet de créer un modèle pour représenter des objets dans le monde réel. En d’autres termes, une classe est une sorte de plan, ou de modèle, à partir duquel des objets spécifiques peuvent être créés. Elle définit la structure et le comportement des objets qui en dérivent.

 

1.1 Définition et nature d’une classe

En C#, une classe est définie à l’aide du mot-clé class suivi du nom de la classe. Elle agit comme un conteneur pour des données (champs) et des méthodes (fonctions) qui décrivent le comportement de l’objet. Une classe permet d’encapsuler les données et les fonctionnalités connexes en un seul bloc, facilitant ainsi la réutilisation du code et la maintenabilité du programme.

 

1.2 Les champs et les propriétés

Les champs sont des variables membres d’une classe utilisées pour stocker des données spécifiques à l’objet. Ils représentent l’état de l’objet. Les propriétés, d’autre part, sont des méthodes d’accès qui permettent de lire, d’écrire ou de manipuler les champs d’une manière contrôlée. Les propriétés offrent un niveau supplémentaire d’encapsulation et de sécurité en permettant de contrôler l’accès aux données de la classe.

 

1.3 Les méthodes

Les méthodes sont des fonctions membres de classe qui définissent le comportement de l’objet. Elles permettent d’effectuer des actions spécifiques, de manipuler les données de la classe, et d’interagir avec d’autres objets du programme. Les méthodes jouent un rôle crucial dans la définition des fonctionnalités de l’objet.

 

1.4 Les constructeurs

Un constructeur est une méthode spéciale appelée lorsqu’un nouvel objet de la classe est créé. Il initialise l’état initial de l’objet en affectant des valeurs aux champs ou en effectuant d’autres opérations nécessaires. Une classe peut avoir plusieurs constructeurs avec différentes signatures, ce qui permet de créer des objets de différentes manières.

 

1.5 Exemple de déclaration de classe

Voici un exemple de déclaration de classe en C#:

public class Voiture
{
    // Champs
    public string Marque;
    public string Modele;
    private int AnneeDeFabrication;

    // Propriétés
    public int AnneeDeFabricationPropriete
    {
        get { return AnneeDeFabrication; }
        set { AnneeDeFabrication = value; }
    }

    // Méthodes
    public void Demarrer()
    {
        Console.WriteLine(« La voiture démarre ! »);
    }
    public void Arreter()
    {
        Console.WriteLine(« La voiture s’arrête ! »);
    }

    // Constructeur
    public Voiture(string marque, string modele, int annee)
    {
        Marque = marque;
        Modele = modele;
        AnneeDeFabrication = annee;
    }
}

2. Déclaration et structure d’une classe C#

Plongeons plus en profondeur dans la déclaration et la structure d’une classe en C#. Nous examinerons la syntaxe de base pour déclarer une classe, les membres qu’elle peut contenir, ainsi que les différents types de membres qui peuvent être définis.

 

2.1 Déclaration d’une classe

En C#, une classe est définie en utilisant le mot-clé class, suivi du nom de la classe et d’un bloc de code délimité par des accolades {}. Voici la syntaxe générale pour déclarer une classe en C# :

public class NomDeLaClasse
{
    // Membres de la classe (champs, propriétés, méthodes, constructeurs, etc.)
}

Le mot-clé public ici est un modificateur d’accès qui indique que la classe est accessible depuis n’importe où dans le code.

2.2 Membres d’une classe

Les classes en C# peuvent contenir différents types de membres qui définissent à la fois les données (état) et le comportement de l’objet.

2.2.1 Champs (Fields)

Les champs sont des variables membres d’une classe utilisées pour stocker les données spécifiques à l’objet. Ils représentent l’état de l’objet. Les champs sont définis en spécifiant leur type et leur nom :

public class Personne
{
    public string Nom;
    public int Age;
}

2.2.2 Propriétés (Properties)

Les propriétés sont des méthodes d’accès qui permettent de lire, d’écrire ou de manipuler les champs de la classe d’une manière contrôlée. Elles offrent un moyen d’encapsuler l’accès aux données et d’appliquer des règles lors de la récupération ou de la modification des valeurs. Les propriétés sont définies à l’aide du mot-clé get (pour récupérer la valeur) et/ou set (pour définir la valeur):

public class CompteBancaire
{
    private double solde;
    public double Solde
    {
        get { return solde; }
        set
        {
            if (value >= 0)
                solde = value;
        }
    }
}

2.2.3 Méthodes (Methods)

Les méthodes sont des fonctions membres de classe qui définissent le comportement de l’objet. Elles permettent d’effectuer des actions spécifiques et d’interagir avec les données de la classe. Les méthodes sont définies avec une signature spécifiant le type de retour, le nom de la méthode et éventuellement des paramètres :

public class Calculatrice
{
    public int Additionner(int a, int b)
    {
        return a + b;
    }
}

2.2.4 Constructeurs (Constructors)

Les constructeurs sont des méthodes spéciales qui sont appelées lorsqu’un nouvel objet de la classe est créé. Ils permettent d’initialiser l’état initial de l’objet en affectant des valeurs aux champs ou en effectuant d’autres opérations nécessaires :

public class Voiture
{
    public string Marque;
    public string Modele;

    public Voiture(string marque, string modele)
    {
        Marque = marque;
        Modele = modele;
    }
}

2.3 Modificateurs d’accès

Les modificateurs d’accès (public, private, protected, etc.) contrôlent l’accessibilité des membres d’une classe à partir d’autres parties du code. Voici les principaux modificateurs d’accès :

public: Le membre est accessible depuis n’importe où dans le code.

private: Le membre est accessible uniquement à l’intérieur de la classe elle-même. C’est le modificateur d’accès par défaut pour les membres d’une classe.

protected: Le membre est accessible à l’intérieur de la classe et de ses classes dérivées (héritage).

internal: Le membre est accessible à l’intérieur de l’assembly (assemblage) dans lequel il est défini.

 

2.4 Exemple de déclaration complète d’une classe

Voici un exemple de déclaration complète d’une classe en C# incluant différents types de membres :

public class Employe
{
    // Champs
    private string nom;
    private int age;

    // Propriétés
    public string Nom
    {
        get { return nom; }
        set { nom = value; }
    }
    public int Age
    {
        get { return age; }
        set
        {
            if (value >= 18)
                age = value;
        }
    }

    // Méthodes
    public void AfficherInformations()
    {
        Console.WriteLine($ »Nom: {Nom}, Age: {Age} »);
    }

    // Constructeur
    public Employe(string nom, int age)
    {
        Nom = nom;
        Age = age;
    }
}

3. Encapsulation et modificateurs d’accès en C# boucle for en C#

L’encapsulation est un concept clé de la programmation orientée objet (POO) qui permet de regrouper les données (champs) et les méthodes (comportements) associées dans une classe, tout en contrôlant l’accès à ces membres depuis l’extérieur de la classe. Les modificateurs d’accès jouent un rôle essentiel dans la mise en œuvre de l’encapsulation en C#. Dans cette section, nous allons explorer plus en détail l’encapsulation et les différents modificateurs d’accès disponibles en C#.

 

3.1 Encapsulation en POO

L’encapsulation permet de cacher les détails internes de l’implémentation d’une classe et de n’exposer que les fonctionnalités essentielles à l’extérieur. Cela garantit que les autres parties du code ne peuvent pas accéder directement aux champs d’une classe sans passer par des méthodes spécifiques (propriétés) définies pour cette tâche. L’encapsulation favorise la modularité, la sécurité et la maintenance du code.

 

3.2 Modificateurs d’accès en C#

Les modificateurs d’accès en C# déterminent la visibilité des membres (champs, propriétés, méthodes, etc.) d’une classe depuis d’autres parties du code. Il existe quatre principaux modificateurs d’accès en C#.

3.2.1 public

Le modificateur d’accès public permet d’accéder aux membres depuis n’importe où dans le code, y compris à l’extérieur de la classe. C’est le modificateur d’accès le plus permissif.

public class Exemple
{
    public int ChampPublic;
    public void MethodePublique() { }
}

3.2.2 private

Le modificateur d’accès private limite l’accès aux membres uniquement à l’intérieur de la classe elle-même. C’est le modificateur d’accès par défaut pour les membres d’une classe.

public class Exemple
{
    private int champPrive;
    private void MethodePrivee() { }
}

3.2.3 protected

Le modificateur d’accès protected permet l’accès aux membres depuis la classe elle-même et ses classes dérivées (héritage).

public class ClasseDeBase
{
    protected int ChampProtege;
}

public class ClasseDerivee : ClasseDeBase
{
    public void MethodeDerivee()
    {
        ChampProtege = 42; // Accès autorisé car ChampProtege est protégé
    }
}

3.2.4 internal

Le modificateur d’accès internal rends les membres accessibles uniquement à l’intérieur de l’assembly (assemblage) dans lequel ils sont définis. Un assembly est un fichier binaire (DLL ou EXE) qui contient du code exécutable.

internal class InterneDansAssembly
{
    internal int ChampInterne;
}

3.3 Avantages de l’encapsulation

Sécurité : L’encapsulation protège les données sensibles en limitant leur accès depuis l’extérieur de la classe. Les utilisateurs ne peuvent manipuler les données que via des méthodes spécifiquement conçues à cet effet.

Modularité : En cachant les détails de l’implémentation, l’encapsulation facilite les changements internes à la classe sans affecter les autres parties du code.

Maintenance : L’encapsulation simplifie la maintenance en rendant les modifications et les améliorations plus aisées à réaliser, sans impacter le reste du code.

 

3.4 Utilisation des propriétés pour encapsuler les champs

L’une des pratiques courantes en C# pour appliquer l’encapsulation est d’utiliser des propriétés pour accéder aux champs privés. Cela permet de contrôler l’accès aux données et d’appliquer des règles de validation si nécessaire.

public class CompteBancaire
{
    private double solde;

    public double Solde
    {
        get { return solde; }
        set
        {
            if (value >= 0)
                solde = value;
        }
    }
}

4. Héritage et classes dérivées en c#

L’héritage est l’un des concepts clés de la programmation orientée objet (POO) qui permet à une classe d’hériter des caractéristiques d’une autre classe. La classe d’origine est appelée « classe de base » ou « classe parent », tandis que la classe qui hérite de cette classe de base est appelée « classe dérivée » ou « classe enfant ». Explorons en détail l’héritage et comment créer des classes dérivées en C#.

 

4.1 Introduction à l’héritage

L’héritage permet de créer une hiérarchie de classes où les classes dérivées héritent des propriétés et des comportements de la classe de base. Cela favorise la réutilisation du code, la simplicité de la conception et la maintenance du logiciel. La classe dérivée peut étendre ou spécialiser les fonctionnalités de la classe de base tout en conservant ses caractéristiques.

 

4.2 Syntaxe pour créer une classe dérivée

En C#, pour créer une classe dérivée, nous utilisons le deux-points (:) suivi du nom de la classe de base après le nom de la classe dérivée. La classe dérivée héritera de tous les membres non privés de la classe de base.

public class ClasseDeBase
{
    // Membres de la classe de base
}

public class ClasseDerivee : ClasseDeBase
{
    // Membres de la classe dérivée
}

4.3 Héritage de champs et de méthodes

Une classe dérivée hérite automatiquement de tous les champs et méthodes publics et protégés de la classe de base. Cela signifie que tu peux accéder aux champs et aux méthodes de la classe de base directement depuis la classe dérivée.

public class Vehicule
{
    public string Marque;
    public void Demarrer()
    {
        Console.WriteLine(« Le véhicule démarre ! »);
    }
}

public class Voiture : Vehicule
{
    public void Accelerer()
    {
        Console.WriteLine(« La voiture accélère ! »);
    }
}

Dans cet exemple, la classe Voiture hérite du champ Marque et de la méthode Demarrer de la classe Vehicule. La classe dérivée Voiture ajoute sa propre méthode Accelerer.

4.4 Constructeur de la classe dérivée

Lorsqu’une classe dérivée est créée, le constructeur de la classe de base est appelé automatiquement avant le constructeur de la classe dérivée. Cela garantit que les membres de la classe de base sont correctement initialisés avant que la classe dérivée ne poursuive son initialisation.

public class Animal
{
    public string Espece;
    public Animal(string espece)
    {
        Espece = espece;
    }
}

public class Chien : Animal
{
    public string Nom;
    public Chien(string espece, string nom) : base(espece)
    {
        Nom = nom;
    }
}

Dans cet exemple, la classe Chien hérite de la classe Animal et utilise le mot-clé base pour appeler le constructeur de la classe de base avec l’argument nécessaire.

4.5 Redéfinition de méthodes (Override)

Une classe dérivée peut redéfinir (ou « overrider ») les méthodes de la classe de base en utilisant le mot-clé override. Cela permet à la classe dérivée de fournir une implémentation spécifique de la méthode qui remplace celle de la classe de base.

public class Figure
{
    public virtual void Dessiner()
    {
        Console.WriteLine(« Dessin de la figure… »);
    }
}

public class Cercle : Figure
{
    public override void Dessiner()
    {
        Console.WriteLine(« Dessin du cercle… »);
    }
}

Ici, la classe Cercle redéfinit la méthode Dessiner héritée de la classe Figure, fournissant une nouvelle implémentation spécifique pour dessiner un cercle.

4.6 Le mot-clé base pour accéder à la classe de base

Le mot-clé base peut également être utilisé pour accéder aux membres de la classe de base à partir de la classe dérivée. Cela est utile lorsque tu souhaites appeler une méthode ou accéder à un champ de la classe de base à partir de la classe dérivée.

public class Personne
{
    public virtual void Saluer()
    {
        Console.WriteLine(« Bonjour ! »);
    }
}

public class Etudiant : Personne
{
    public override void Saluer()
    {
        base.Saluer(); // Appelle la méthode Saluer() de la classe de base
        Console.WriteLine(« Je suis un étudiant. »);
    }
}

5. Polymorphisme et interfaces en c#

Le polymorphisme est un concept fondamental de la programmation orientée objet (POO) qui permet à plusieurs classes d’implémenter des fonctionnalités communes via des interfaces. Les interfaces fournissent un moyen d’abstraction puissant pour définir un contrat que les classes doivent suivre. Explorons en détail le polymorphisme et l’utilisation des interfaces en C#.

 

5.1 Polymorphisme

Le polymorphisme permet à des objets de différentes classes de répondre de manière uniforme à une même méthode, même si l’implémentation de cette méthode peut varier d’une classe à une autre. Cela permet de traiter des objets de classes différentes de manière générique et d’écrire du code plus flexible et réutilisable.

 

5.2 Polymorphisme par substitution (Override)

Le polymorphisme par substitution (ou « override ») est obtenu lorsque la classe dérivée fournit une implémentation spécifique d’une méthode déjà définie dans la classe de base. Cela permet à l’objet de la classe dérivée de se comporter de manière spécifique à la classe tout en étant traité comme un objet de la classe de base.

public class Forme
{
    public virtual void Dessiner()
    {
        Console.WriteLine(« Dessin de la forme… »);
    }
}

public class Cercle : Forme
{
    public override void Dessiner()
    {
        Console.WriteLine(« Dessin du cercle… »);
    }
}

public class Carre : Forme
{
    public override void Dessiner()
    {
        Console.WriteLine(« Dessin du carré… »);
    }
}

Dans cet exemple, les classes `Cercle` et `Carre` substituent la méthode `Dessiner` héritée de la classe `Forme`, fournissant ainsi une implémentation spécifique pour dessiner un cercle ou un carré.

5.3 Polymorphisme par interfaces

Les interfaces définissent un contrat que les classes doivent suivre, en spécifiant les méthodes et les propriétés qu’elles doivent implémenter. Les classes qui implémentent une interface doivent fournir une implémentation concrète de toutes les méthodes définies dans l’interface. Cela permet de créer un polymorphisme par interfaces où plusieurs classes peuvent être traitées de manière générique en utilisant l’interface commune.

public interface IVehicule
{
    void Demarrer();
    void Arreter();
}

public class Voiture : IVehicule
{
    public void Demarrer()
    {
        Console.WriteLine(« La voiture démarre… »);
    }
    public void Arreter()
    {
        Console.WriteLine(« La voiture s’arrête… »);
    }
}

public class Moto : IVehicule
{
    public void Demarrer()
    {
        Console.WriteLine(« La moto démarre… »);
    }
    public void Arreter()
    {
        Console.WriteLine(« La moto s’arrête… »);
    }
}

5.4 Utilisation du polymorphisme

Le polymorphisme permet de traiter les objets de différentes classes de manière uniforme en utilisant des mécanismes tels que l’héritage et les interfaces. Cela permet d’écrire un code générique et flexible qui fonctionne avec différentes implémentations d’une même fonctionnalité.

public static void AfficherInformationsVehicule(IVehicule vehicule)
{
    vehicule.Demarrer();
    vehicule.Arreter();
}

static void Main()
{
    Voiture maVoiture = new Voiture();
    Moto maMoto = new Moto();
    AfficherInformationsVehicule(maVoiture); // Appel polymorphique
    AfficherInformationsVehicule(maMoto); // Appel polymorphique
}

Dans cet exemple, nous utilisons la méthode `AfficherInformationsVehicule` pour afficher les informations de démarrage et d’arrêt pour une voiture et une moto. Le polymorphisme nous permet d’appeler cette méthode avec différents types d’objets, et la méthode adaptée sera appelée en fonction du type réel de l’objet passé.

6. Meilleures pratiques de conception de classes en C#

La conception de classes efficaces est essentielle pour créer des applications en C# robustes, maintenables et évolutives. Voici quelques meilleures pratiques pour la conception de classes en C#.

 

6.1 Cohésion élevée et couplage faible

Une classe doit avoir une seule responsabilité clairement définie. C’est ce qu’on appelle la cohésion élevée. Évite de surcharger une classe avec trop de fonctionnalités différentes. En même temps, assure-toi que les classes sont faiblement couplées, c’est-à-dire qu’elles dépendent le moins possible les unes des autres. Cela favorise la réutilisation et facilite les modifications futures.

 

6.2 Encapsulation

Utilise l’encapsulation pour cacher les détails internes de la classe et ne révélez que les fonctionnalités essentielles via des propriétés et des méthodes. Cela permet de contrôler l’accès aux données et d’appliquer des règles de validation si nécessaire.

 

6.3 Utilisation appropriée des modificateurs d’accès

Choisis soigneusement les modificateurs d’accès (public, private, protected, internal) pour les membres de la classe afin de garantir une encapsulation appropriée et de contrôler l’accessibilité des membres depuis d’autres parties du code.

 

6.4 Utilisation de classes abstraites et d’interfaces

Utilise des classes abstraites et des interfaces pour définir des contrats et créer des hiérarchies de classes. Les classes abstraites permettent de définir des méthodes sans les implémenter, tandis que les interfaces définissent des contrats que les classes doivent suivre.

 

6.5 Évite les classes trop volumineuses

Les classes trop grandes peuvent être difficiles à comprendre et à maintenir. Essayez de les diviser en classes plus petites avec des responsabilités clairement définies.

 

6.6 Utilisation de méthodes virtuelles et override

Si tu as besoin de permettre aux classes dérivées de redéfinir le comportement d’une méthode, utilisez le mot-clé `virtual` pour la méthode dans la classe de base et le mot-clé `override` dans la classe dérivée.

 

6.7 Noms de classes significatifs

Donne des noms de classes significatifs et descriptifs qui reflètent leur rôle et leur responsabilité dans le système.

 

6.8 Évitez les dépendances cycliques

Évite les dépendances cycliques entre les classes, car cela peut rendre le code compliqué et difficile à maintenir.

 

6.9 Commentaires et documentation

Ajoute des commentaires appropriés pour expliquer le but et le fonctionnement des classes, des méthodes et des propriétés. La documentation du code est essentielle pour permettre aux autres développeurs de comprendre rapidement le code et de l’utiliser correctement.

 

6.10 Testabilité

Conçois tes classes de manière à ce qu’elles puissent être facilement testées à l’aide de tests unitaires. Divise les responsabilités en méthodes distinctes et évite les dépendances externes dans les classes lorsque cela est possible.

La maîtrise des classes en C# est une compétence précieuse pour tout développeur, que ce soit pour les développeurs juniors cherchant à renforcer leurs bases en programmation orientée objet ou pour les développeurs chevronnés partageant leurs connaissances avec la communauté des développeurs.

QCM

Testez vos connaissances sur ce sujet

TL;DR

Les classes en C# sont l’un des piliers fondamentaux de la programmation orientée objet. Elles permettent de regrouper des données (champs) et des méthodes (comportements) liées en une seule entité, favorisant ainsi l’encapsulation, la modularité, et la réutilisation du code.