Langage C# – Des délégués aux expressions lambda

Dans le langage C#, les délégués sont des types de données qui permettent de créer des objets pointant vers du code. Ce concept a révolutionné le développement de logiciels en permettant aux procédures et fonctions de s’échanger non seulement des données, mais des blocs d’instruction en C#.

D’un point de vue historique, les délégués existent depuis la première version du langage C#. En 2005, Microsoft propose une solution permettant de simplifier leur mise en œuvre avec les méthodes anonymes. En 2008, Microsoft propose une évolution majeure avec les expressions lambda et les délégués génériques Func (retournant une valeur) et Action (ne retournant pas de valeur).

Les délégués sont utilisés pour répondre à différents besoins :

  • Rendre le comportement des méthodes personnalisables en fonction de la méthode les appelant
  • Méthodes de callback de traitements asynchrones
  • Les événements

Voici un simple exemple permettant de mettre en œuvre les délégués pour permettre de factoriser du code entre différentes méthodes. Voici deux méthodes dont l’implémentation est très proche :

  • Une première méthode permettant de démarrer un véhicule :
  • public void DemarrerVehicule()
    {
        // Variables locales.
        Vehicule oVehicule;

        // Initialisation.
        oVehicule = this.VehiculeSelectionne;

        if (oVehicule != null)
        {
            oVehicule.Demarrer();

            Trace.WriteLine("Le véhicule est démarré");

        }

        // ...
    }
  • Une seconde permettant d’arrêter un véhicule :
  • public void ArreterVehicule()
    {
        // Variables locales.
        Vehicule oVehicule;

        // Initialisation.
        oVehicule = this.VehiculeSelectionne;

        if (oVehicule != null)
        {
            oVehicule.Arreter();

            Trace.WriteLine("Le véhicule est arrêté");

        }

        // ...
    }

Il est possible d’ajouter des méthodes supplémentaires permettant d’accélérer, de freiner et de garer un véhicule sur le même modèle.

Qu’est-ce qui diffère entre ces méthodes ? Deux choses : l’action exécutée sur le véhicule ainsi que le message enregistré dans les logs. Pour factoriser le code entre ces deux méthodes, il est nécessaire de créer la méthode suivante :

public void ExecuterActionVehicule(Action<Vehicule> aAction, string aMessageLog)
{
    // Variables locales.
    Vehicule oVehicule;

    // Initialisation.
    oVehicule = this.VehiculeSelectionne;

    if (oVehicule != null)
    {
        // Action sur le véhicule.
        aAction.Invoke(oVehicule);
                               
        // Log.
        Trace.WriteLine(aMessageLog);
    }

    // ...
}

Cette méthode en paramètre un message et un délégué pointant vers un bloc d’instructions acceptant en paramètre un véhicule. Cette méthode permet de factoriser les méthodes DemarrerVehicule et ArreterVehicule de la manière suivante :

public void DemarrerVehicule()
{
    this.ExecuterActionVehicule(obj => obj.Demarrer(), "Le véhicule est démarré");
}

public void ArreterVehicule()
{
    this.ExecuterActionVehicule(obj => obj.Arreter(), "Le véhicule est arrêté");
}

Dans ces méthodes, obj est de type Vehicule et représente le véhicule sélectionné. Cet objet est utilisé dans des expressions lambda qui indiquent l’action à exécuter sur ce même objet. Ainsi, une méthode appelle une autre méthode en lui passant en paramètre un bloc de code.

About: James RAVAILLE

Travaillant avec la plateforme Microsoft .NET depuis 2002, j’alterne les missions de formation et d’ingénierie avec cette plateforme. J’écris ce blog pour transmettre mes connaissances à tout développeur, qu’il soit débutant ou expérimenté.