Cet article traite d’un sujet important concernant les types délégués en C# (csharp).
Il fera sans doute partie d’une série d’article sur les bases de CSharp.
Nous allons donc voir ce que sont les delegates et pourquoi ils sont très importants dans le développement d’application .NET.
Qu’est-ce qu’un type delegate ?
En fait, un type delegate est un concept très simple : c’est un type qui permet de référencer une méthode d’une classe.
Grâce aux delegates, vous pouvez transmettre une méthode comme paramètre (c’est un peu l’équivalent des pointeurs de fonction en C / C++ par exemple).
Un type délégué (delegate en anglais) est toujours associé à la signature d’une méthode.
Seules les méthodes ayant la même signature pourront être utilisées avec ce délégué.
delegate est aussi un mot clé du langage C# (csharp) qui permet de déclarer un delegate.
Pour déclarer un delegate en CSharp, voici ce qu’il faut faire :
- dans votre classe, vous utilisez le mot clé delegate suivi de la signature de la méthode associée,
- le nom de la méthode indiquée dans la signature sera le nom de votre delegate,
- vous pouvez éventuellement ajouter un indicateur de visibilité au début (private, public ou protected par exemple).
Voici un exemple de code qui permet de déclarer un delegate en C# :
[csharp] public class MaClasse{
public delegate int Calculer(List<int> elements);
}
[/csharp]
Dans cet exemple, je déclare un delegate pour une méthode qui prend en argument une liste d’int et qui retourne un int.
Toutes les méthodes correspondantes à cette signature pourront être utilisée avec ce delegate.
Comment utiliser un delegate ?
Après avoir déclaré un type délégué, il faut désormais l’utiliser votre delegate dans votre code CSharp.
Un type delegate peut être utilisé comme n’importe quel type en C# : dans les méthodes (arguments en entrée, paramètre de retour) ou dans les classes (propriété ou membre).
Voici un exemple d’utilisation de type délégué en C# (suite de l’exemple précédent) :
[csharp] int MaMethodeDeCalcul(List<int> elements){
return elements.Count;
}
void Main()
{
MaClasse.Calculer delegateCalculer = new MaClasse.Calculer(MaMethodeDeCalcul);
MaClasse instance = new MaClasse();
// ici, j’appelle la méthode Traiter de MaClasse
// en passant le délégué comme argument.
instance.Traiter(delegateCalculer);
// vous auriez aussi pu écrire ceci :
// instance.Traiter(new MaClasse.Calculer(MaMethodeDeCalcul));
// ou même ceci (depuis les dernières versions de C#) :
// instance.Traiter(MaMethodeDeCalcul);
}
[/csharp]
Ok, jusque là, vous allez me dire : bon, mais ça sert à quoi un delegate ?
L’utilisation la plus courante des types délégués
Les types délégués en C# permettent de passer des méthodes comme argument lors des appels.
Il est donc possible de créer des comportements différents pour un même code.
En effet, les types délégués sont des points d’extension de votre code.
Il sera possible de changer le comportement d’un morceau de code simplement en passant un autre delegate.
Voici un exemple très simple :
- Vous avez une classe qui effectue des calculs sur une série de nombres,
- Une méthode « Calculer » prend en argument une liste d’entiers et deux delegates : AvantTraitementDelegate et ApresTraitementDelegate,
- Ces deux delegates ont pour fonction de pouvoir filtrer ou modifier une série d’éléments avant ou après un traitement,
- La méthode Calculer pourra être appellée plusieurs fois dans votre application avec des références vers différentes méthodes.
Pour mieux comprendre, je vous propose un exemple qui montre deux appels différents :
[csharp]public MaClasseDeTraitement
{
public delegate void AvantTraitementDelegate(List<int> elements);
public delegate List<int> ApresTraitementDelegate(List<int> elements);
// Méthode de calcul simple (inverser la liste)
public List<int> Calculer(List<int> elements,
AvantTraitementDelegate avant, ApresTraitementDelegate apres)
{
List<int> copie = new List<int>(elements);
// appel du delegate si défini
if (avant != null) avant(copie);
copie.Reverse();
// appel du delegate si défini
if (apres != null) copie = apres(copie);
return copie;
}
}
// Cette méthode ajoute un à chaque élément
void AjouterUn(List<int> elements)
{
for (int i = 0; i < elements.Count; i++)
elements[i] = elements[i] + 1;
}
// Cette méthode supprime les 0 de la liste
List<int> SupprimerZero(List<int> elements)
{
elements.Remove(0);
return elements;
}
void Main()
{
MaClasseDeTraitement traitement = new MaClasseDeTraitement();
List<int> elements = new List<int>();
// TODO: remplir la liste ici
// Ici, j’appelle Calculer en passant les elements
// mais sans delegate
List<int> resultat1 = traitement.Calculer(elements, null, null);
// Cette fois-ci, on effectue l’appel mais
// en passant deux delegates :
// Le premier effectue un pré-traitement (ajouter un à chaque élément),
// Le second supprimer les 0 de la liste.
List<int> resultat2 = traitement.Calculer(elements, AjouterUn, SupprimerZero);
}
[/csharp]
Comme vous le voyez, il est possible de faire des opérations différentes en fonction des méthodes passées en paramètre.
- Dans le premier cas, on appelle Calculer sans méthode de traitement.
- Dans le second cas, on appelle Calculer avec les deux méthodes de traitement, ce qui va donc produire un résultat complètement différent.
Pourquoi les delegates sont-ils si importants ?
Les types délégués sont importants en C# pour deux raisons essentiellement :
- Tout d’abord, car ils sont utilisés partout dans le framework Dotnet. Il est donc très important de bien comprendre ce concept pour utiliser le framework .NET correctement.
- Les types délégués sont utilisés pour mettre en place le principe de l’Ouvert-fermé (j’en parle dans l’article Concevoir des applications SOLID avec OCP).
Comment aller plus loin ?
Si vous souhaitez utiliser le framework .NET de manière optimale, je vous conseille fortement de pratiquer et d’essayer d’utiliser puis de créer vos propres delegates.
C’est pour ça que je vous ai préparé, en bonus de cet article, une fiche méthode qui résume l’essentiel et qui vous propose des exercices pour aller plus loin dans la pratique.
[sociallocker] Télécharger le bonus complémentaire[/sociallocker]
Enfin un article qui me permet de comprendre facilement le comportement des delegates grâce à des exemples simples
Merci beaucoup
Merci Morgan, je vous invite à suivre le prochain sur les events.
Classique mais c’est impressionant le nombre de personne faisant du c# et ne connaissant pas (ou alors ne les utilisant jamais) les délégates ! Un rappel ne fait pas de mal.
Effectivement les delegates sont importants et puissants en C#. C’est presque la base du langage et du framework .NET.
Bonjour,
Tout d’abord merci, c’est vraiment une notion que je trouvais super abstraite et que j’apréhende mieux maintenant. Sinon, dans le code que tu donnes, je crois que la méthode AjouterUn est en double, la deuxième ne devrait pas s’appeler SupprimerZero?
Sinon super travail, j’aime aussi beaucoup l’idée de proposer des katas pour s’améliorer.
Bonne continuation,
Jonathan
Bonjour Jonathan,
Merci de ton retour. Je viens de corriger l’erreur.
Hello, Il y a un petit souci au niveau du code, la méthode supprimer zéro n’as pas la meme signature que ton delegate ApresTraitementDelegate. il y a donc un petit souci avec ton exemple.
Merci, effectivement, il faut retourner « List