Mémo Programmation C# : délégué

Un délégué (delegate) est une variable qui « pointe » vers une méthode.

Le délégué nous permet de définir un modèle de signature de méthode, puis grâce à lui, nous pourrons pointer vers n’importe que méthode qui respecte ce modèle de signature.

Les délégués sont très similaire aux pointeurs mais plus complets, dans le sens où il est possible de leurs faire exécuter une série de fonctions à la suite des autres.

Exemple :

class Program
    {
        delegate void DT(); //définition de type du délégué DT

        static void Main(string[] args)
        {
            DT del; // déclaration de la variable del de type DT
            del = new DT(doItFirst); //ajout à del une référence à la fonction doItFirst
            del += new DT(doItInSecond); //ajout à del une référence à doItInSecond
            del(); //exécute le délégué del

            Console.ReadLine();
        }

        static void doItFirst()
        {
            Console.WriteLine("-> fonction exécutée en premier");
        }

        static void doItInSecond()
        {
            Console.WriteLine("-> fonction exécutée en deuxième");
        }
    }

Ce qui affiche en sortie :

del1

Ici, j’ai déclaré des fonction statiques grâce au mot-clé « static » afin de ne créer aucun objet pour la simplicité de ce premier exemple.

Vous l’avez remarqué, il est possible d’ajouter ou de supprimer, n’importe quand, des fonctions à la liste des fonctions référencées par le délégué pour peut que la signature corresponde.

 

Continuons vers un peu plus complexe :

public class ClassSample //classe contenant les fonctions à passer au délégué
    {
        public void doItIn(int number)
        {
            Console.WriteLine(string.Format("-> fonction exécutée en {0}", number));
        }

        public void paramPassed(int number)
        {
            Console.WriteLine(string.Format("-> le parmètre était {0}", number));
        }
    }

public class Program
    {
        delegate void DT();
        delegate void DTP(int number); //déclaration du délégué

        static void Main(string[] args)
        {
            DT del = new DT(doItFirst);
            del += new DT(doItInSecond);
            del();

            ClassSample cs = new ClassSample(); //Instanciation de l'objet cs
            DTP delparam = new DTP(cs.doItIn); //ajoute une référence à la fonction doItIn
            delparam += new DTP(cs.paramPassed); //ajoute une référence à paramPassed
            delparam(3); //exécute le délégué delparam avec en paramètre 3

            Console.ReadLine();
        }

        static void doItFirst()
        {
            Console.WriteLine("-> fonction exécutée en premier");
        }

        static void doItInSecond()
        {
            Console.WriteLine("-> fonction exécutée en deuxième");
        }
    }

Ce qui donne en sortie :
del2

 

Le délégué aurait tout aussi bien pu être définit dans la classe « ClassSample », et on l’aurait donc manipuler comme ceci :

//déclaration dans la classe ClassSample
public delegate void DTP(int number); 

//utilisation dans la fonction Main de la classe Program
ClassSample cs = new ClassSample();
ClassSample.DTP delparam = new ClassSample.DTP(cs.doItIn);
delparam += new ClassSample.DTP(cs.paramPassed);
delparam(3);

Un peu plus de détails…

Implicitement le délégué exécute sa méthode Invoke() lors qu’il est appelé.

//déclaration dans la classe ClassSample
public delegate void DTP(int number);

//utilisation dans la fonction Main de la classe Program
ClassSample cs = new ClassSample();
ClassSample.DTP delparam = new ClassSample.DTP(cs.doItIn);
delparam += new ClassSample.DTP(cs.paramPassed);
delparam.Invoke(3);

 

Mais il peut être interessant de pouvoir l’exécuter dans un thread différent, on fera donc un appel asynchrone via la méthode BeginInvoke de notre délégué.

 

public class Program
{
    public delegate void DTP(int number);

    public static void Main(string[] args)
    {
        ClassSample cs = new ClassSample();
        DTP delparam = new DTP(cs.doItIn);
        AsyncCallback myCallBack = new AsyncCallback(EndAsyncInvoke);
        delparam.BeginInvoke(3,  myCallBack, null);

        Console.Read();
    }

    public static void EndAsyncInvoke(IAsyncResult result)
    {
        Console.WriteLine("EndAsyncInvoke is complete ? " +result.IsCompleted.ToString());
    }
}

public class ClassSample
{
    public void doItIn(int number)
    {
        Console.WriteLine(string.Format("-> fonction exécutée en {0}", number));
    }
    public void paramPassed(int number)
    {
        Console.WriteLine(string.Format("-> le paramètre était {0}", number));
    }
}

delegue_invoke

J’espère avoir pu expliquer clairement par l’exemple ce petit mémo !