Langage C# – Créer facilement des objets qui pointent vers du code (délégués et expressions lambda)

Depuis 2008, au travers du Framework .NET, Microsoft propose deux délégués génériques permettant créer facilement des objets pointant vers du code : Func et Action. Les délégués (sous une autre forme) existaient déjà auparavant. Leur apparition a révolutionné le développement d’application en permettant :

  • Aux procédures et fonctions d’accepter non seulement des données en paramètre, mais aussi du code.
  • Aux fonctions de retourner du code.

Les expressions lambda sont une évolution des délégués.

Quelle est la différence entre ces deux délégués ?

  • Func est un « délégué fonction », autrement dit il pointe vers une fonction, autrement dit un bloc de code qui retourne obligatoirement une donnée ou un objet. Les n-1 premiers types fournis représentent les types des paramètres d’entrée ; le dernier type représente le type de retour. Exemple :
    Func<int, int, long> fct;

    L’objet fct pointe vers un bloc de code qui accepte deux paramètres de type int et retourne une donnée de type long.

  • Action est un « délégué fonction », autrement dit il pointe vers une procédure, autrement dit un bloc de code qui ne retourne rien. Les n types fournis représentent les types des paramètres d’entrée. Exemple :
    Action<int, bool> proc;

    L’objet proc pointe vers un bloc de code qui accepte un paramètre de type int et un second de type bool.

Comment les utiliser ?
La méthode GetOperation retourne un objet qui pointe vers une fonction acceptant en paramètres deux données de type int et retournant une donnée de type long dont le contenu est une opération mathématique qui dépend de la valeur de l’énumération passée en paramètre.

public enum OperationMathematiques
{
    Addition = 1,
    Soustraction = 2,
    Multiplication = 3,
    Division = 4
}

public class OpMaths
{
    public static Func<int, int, long> GetOperation (OperationMathematiques aOp)
    {
        // Variables locales.
        Func<int, int, long> fct = null;

        switch (aOp)
        {
            case OperationMathematiques.Addition:
                {
                    fct = (aNombre1, aNombre2) => aNombre1 + aNombre2;
                    break;
                }
            case OperationMathematiques.Soustraction:
                {
                    fct = (aNombre1, aNombre2) => aNombre1 - aNombre2;
                    break;
                }
            case OperationMathematiques.Multiplication:
                {
                    fct = (aNombre1, aNombre2) => aNombre1 * aNombre2;
                    break;
                }
            case OperationMathematiques.Division:
                {
                    fct = (aNombre1, aNombre2) => aNombre1 / aNombre2;
                    break;
                }
        }

        // Retour.
        return fct;
    }
}

Astuce : Si fct (expression lambda) pointe vers plusieurs instructions, il est alors nécessaire d’utiliser les accolades :

fct = (aNombre1, aNombre2) =>
{
    // Autres instructions.
    return aNombre1 / aNombre2;
};

Pour utiliser la fonction GetOperation :

Func<int, int, long> opMaths = OpMaths.GetOperation(OperationMathematiques.Multiplication);

La variable opMaths contient donc un bloc de code permettant de réaliser une multiplication. Pour demander son exécution :

long r = opMaths.Invoke(10, 3);
ou (la méthode Invoke est optionnelle) :
long r = opMaths(10, 3);

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é.