Notes
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de modifier des répertoires.
Un délégué définit un type qui représente des références aux méthodes qui ont une liste de paramètres particulière et un type de retour. Méthode (statique ou instance) dont la liste de paramètres et la correspondance de type de retour peuvent être affectées à une variable de ce type, puis appelée directement (avec les arguments appropriés) ou passée en tant qu’argument lui-même à une autre méthode, puis appelée. L’exemple suivant illustre l’utilisation des délégués.
using System;
using System.Linq;
public class Program
{
public delegate string Reverse(string s);
static string ReverseString(string s)
{
return new string(s.Reverse().ToArray());
}
static void Main(string[] args)
{
Reverse rev = ReverseString;
Console.WriteLine(rev("a string"));
}
}
- La
public delegate string Reverse(string s);
ligne crée un type délégué d’une méthode qui prend un paramètre de chaîne, puis retourne un paramètre de chaîne. - La
static string ReverseString(string s)
méthode, qui a exactement la même liste de paramètres et le même type de retour que le type délégué défini, implémente le délégué. - La
Reverse rev = ReverseString;
ligne indique que vous pouvez affecter une méthode à une variable du type délégué correspondant. - La
Console.WriteLine(rev("a string"));
ligne montre comment utiliser une variable d’un type délégué pour appeler le délégué.
Pour simplifier le processus de développement, .NET inclut un ensemble de types délégués que les programmeurs peuvent réutiliser et n’ont pas à créer de nouveaux types. Ces types sont Func<>
, Action<>
et Predicate<>
, et ils peuvent être utilisés sans avoir à définir de nouveaux types délégués. Il existe des différences entre les trois types concernant la manière dont ils étaient censés être utilisés.
-
Action<>
est utilisé lorsqu’il est nécessaire d’effectuer une action à l’aide des arguments du délégué. La méthode qu’il encapsule ne renvoie aucune valeur. -
Func<>
est généralement utilisé lorsque vous avez une transformation en main, autrement dit, vous devez transformer les arguments du délégué en un résultat différent. Les projections sont un bon exemple. La méthode qu’elle encapsule retourne une valeur spécifiée. -
Predicate<>
est utilisé lorsque vous devez déterminer si l’argument satisfait à la condition du délégué. Elle peut également être écrite en tant queFunc<T, bool>
, ce qui signifie que la méthode retourne une valeur booléenne.
Nous pouvons maintenant reprendre notre exemple ci-dessus et le réécrire en utilisant le Func<>
délégué plutôt qu'un type personnalisé. Le programme continuera à s’exécuter exactement de la même façon.
using System;
using System.Linq;
public class Program
{
static string ReverseString(string s)
{
return new string(s.Reverse().ToArray());
}
static void Main(string[] args)
{
Func<string, string> rev = ReverseString;
Console.WriteLine(rev("a string"));
}
}
Pour cet exemple simple, l’utilisation d’une méthode définie en dehors de la Main
méthode semble un peu superflue. .NET Framework 2.0 a introduit le concept de délégués anonymes, ce qui vous permet de créer des délégués « inline » sans avoir à spécifier de type ou de méthode supplémentaire.
Dans l’exemple suivant, un délégué anonyme filtre une liste uniquement sur les nombres pairs, puis les imprime dans la console.
using System;
using System.Collections.Generic;
public class Program
{
public static void Main(string[] args)
{
List<int> list = new List<int>();
for (int i = 1; i <= 100; i++)
{
list.Add(i);
}
List<int> result = list.FindAll(
delegate (int no)
{
return (no % 2 == 0);
}
);
foreach (var item in result)
{
Console.WriteLine(item);
}
}
}
Comme vous pouvez le voir, le corps du délégué n’est qu’un ensemble d’expressions, comme n’importe quel autre délégué. Mais au lieu d’être une définition distincte, nous l’avons introduit ad hoc dans notre appel à la List<T>.FindAll méthode.
Toutefois, même avec cette approche, il y a encore beaucoup de code que nous pouvons jeter. C’est là que les expressions lambda entrent en jeu. Les expressions lambda, ou simplement « lambdas » pour un court terme, ont été introduites dans C# 3.0 comme l’un des principaux blocs de construction de la requête intégrée de langage (LINQ). Il s’agit simplement d’une syntaxe plus pratique pour l’utilisation de délégués. Ils déclarent une liste de paramètres et un corps de méthode, mais n’ont pas d’identité formelle de leur propre, sauf s’ils sont affectés à un délégué. Contrairement aux délégués, ils peuvent être directement assignés comme partie droite de l’enregistrement d’événement ou dans diverses clauses et méthodes LINQ.
Étant donné qu’une expression lambda n’est qu’une autre façon de spécifier un délégué, nous devons pouvoir réécrire l’exemple ci-dessus pour utiliser une expression lambda au lieu d’un délégué anonyme.
using System;
using System.Collections.Generic;
public class Program
{
public static void Main(string[] args)
{
List<int> list = new List<int>();
for (int i = 1; i <= 100; i++)
{
list.Add(i);
}
List<int> result = list.FindAll(i => i % 2 == 0);
foreach (var item in result)
{
Console.WriteLine(item);
}
}
}
Dans l’exemple précédent, l’expression lambda utilisée est i => i % 2 == 0
. Là encore, il s’agit simplement d’une syntaxe pratique pour l’utilisation de délégués. Ce qui se passe sous les couvertures est similaire à ce qui se passe avec le délégué anonyme.
Là encore, les lambda sont simplement des délégués, ce qui signifie qu’ils peuvent être utilisés comme gestionnaire d’événements sans aucun problème, comme l’illustre l’extrait de code suivant.
public MainWindow()
{
InitializeComponent();
Loaded += (o, e) =>
{
this.Title = "Loaded";
};
}
L’opérateur +=
dans ce contexte est utilisé pour s’abonner à un événement. Pour plus d’informations, consultez Comment s’abonner et se désabonner des événements.