Remarque
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.
Tip
Vous débutez avec le développement de logiciels ? Commencez par commencer par les didacticiels De prise en main . Développez des compétences essentielles en types et méthodes avant d’utiliser des expressions lambda.
Parfois, vous souhaitez passer un petit morceau de comportement, une fonction, directement à une autre méthode. Par exemple, vous pouvez filtrer une liste, mais la condition de filtrage change en fonction de la situation. Au lieu d’écrire une méthode nommée distincte pour chaque condition possible, vous passez la condition elle-même en tant qu’argument.
Les expressions lambda sont la fonctionnalité C# qui rend cela possible. Une expression lambda est une fonction compacte et inline que vous écrivez sans lui donner de nom. Vous utilisez l’opérateur => de flèche pour séparer la liste des paramètres du corps :
x => x * 2
Lecture de gauche à droite : x est le paramètre d’entrée, => signifie « va à », et x * 2 est le corps. Elle calcule la valeur retournée. En l’absence de paramètres ou de plusieurs, encapsulez-les entre parenthèses : () => 42 ou (left, right) => left + right.
Les délégués prennent en charge les expressions lambda
Pour utiliser une expression lambda, le compilateur C# doit connaître deux éléments : les types des paramètres et le type de retour. Cette description, les types de paramètres plus le type de retour, sont appelés un type délégué.
Un type délégué est un type qui représente une signature de méthode. Une variable d’un type délégué peut contenir n’importe quelle méthode dont les types de paramètres et le type de retour sont identiques, qu'il s'agisse d’une expression lambda ou d’une méthode nommée.
Vous déclarez un type délégué avec le delegate mot clé :
delegate int Transform(int value);
Cette déclaration indique : «Transform est un type délégué pour les méthodes qui acceptent un int et retournent un int». Vous pouvez ensuite affecter une expression lambda ou une méthode nommée à une variable de ce type :
Transform doubler = x => x * 2; // assign a lambda expression
Transform squarer = Square; // assign a named method
Console.WriteLine(doubler(5)); // 10
Console.WriteLine(squarer(5)); // 25
static int Square(int value) => value * value;
Les deux doubler et squarer contiennent une valeur de type Transform. Vous les invoquez exactement comme des méthodes traditionnelles. Le compilateur vérifie que tout ce que vous affectez correspond à la signature déclarée.
Types délégués intégrés : Func et Action
La déclaration d’un type délégué personnalisé pour chaque situation peut être répétitive. .NET fournit deux familles de types délégués génériques, Func et Action, qui couvrent la plupart des scénarios, de sorte que vous devez rarement utiliser le mot clé delegate vous-même.
Les deux familles sont disponibles dans des versions avec zéro à seize paramètres de type d’entrée, de sorte qu’elles peuvent accueillir n’importe quel nombre d’entrées. La principale différence entre les deux familles est la suivante :
-
System.Func<T,TResult> (et
Func<T1, T2, TResult>, et ainsi de suite) représente une méthode qui retourne une valeur. Le dernier paramètre de type est toujours le type de retour ; tous les premiers sont des types d’entrée. -
System.Action<T> (et
Action<T1, T2>, et ainsi de suite) représente une méthode qui ne retourne rien (void). Tous les paramètres de type sont des types d’entrée. System.Action sans paramètre de type représente une méthode sans entrées et aucune valeur de retour.
Par exemple, Func<int, int, int> décrit une méthode avec deux int entrées et un int résultat.
Action<string> décrit une méthode avec une string entrée et aucune valeur de retour.
Func<int, int, int> add = (left, right) => left + right;
Action<string> report = message => Console.WriteLine($"Report: {message}");
int total = add(5, 9);
report($"5 + 9 = {total}");
Utilisez des noms de paramètres descriptifs dans des lambdas afin que les lecteurs puissent comprendre l’intention sans analyser le corps complet de la méthode.
Passer une expression lambda à une méthode
Lorsqu'une méthode déclare un paramètre Func ou Action, les appelants passent une expression lambda qui correspond à ce type de délégué. Le compilateur vérifie que les types de paramètres et le type de retour de l’lambda correspondent au type délégué déclaré. S’ils ne correspondent pas, le code ne se compile pas.
int[] numbers = [1, 2, 3, 4, 5, 6];
int[] evenNumbers = Filter(numbers, value => value % 2 == 0).ToArray();
Console.WriteLine(string.Join(", ", evenNumbers));
La Filter méthode déclare un Func<int, bool> paramètre nommé predicate. Le type Func<int, bool> indique aux appelants la forme attendue : une int entrée, un bool résultat. L’appelant passe value => value % 2 == 0 en tant qu’argument. Ce modèle s’affiche dans LINQ et dans de nombreuses API .NET.
Conserver les expressions lambda autonomes
Une expression lambda peut référencer des variables à partir du code environnant. La capture signifie que l’lambda contient une référence à une variable déclarée en dehors de son propre corps. La combinaison de l’expression lambda et des variables qu’elle capture est appelée fermeture.
Quand vous n’avez pas besoin de capturer quoi que ce soit, ajoutez le static modificateur à l’expression lambda. Une lambda statique ne peut utiliser que ses propres paramètres et valeurs déclarés à l’intérieur de son corps. Il ne peut pas capturer les variables locales ou l’état de l’instance à partir de l’étendue englobante.
Func<int, bool> isEven = static value => value % 2 == 0;
Console.WriteLine(isEven(14));
Console.WriteLine(isEven(15));
Les lambdas statiques clarifient l'intention et évitent les captures accidentelles.
Utiliser les paramètres d’abandon lorsque les entrées ne sont pas pertinentes
Parfois, une signature de délégué inclut des paramètres dont vous n’avez pas besoin. Utilisez l’abandon _ pour signaler explicitement ce choix.
Les exemples courants incluent des gestionnaires d’événements où vous n'utilisez pas sender ou EventArgs, des callbacks où vous avez uniquement besoin de certaines entrées, et des surcharges LINQ qui fournissent un index que vous n’utilisez pas.
Action<int, int, string> statusUpdate = (_, _, message) => Console.WriteLine(message);
statusUpdate(200, 42, "Operation completed");
Les rejets améliorent la lisibilité, car ils indiquent quels paramètres sont importants.
Les événements fournissent des notifications facultatives
Un événement est un mécanisme utilisé par un objet ( l’éditeur) pour notifier d’autres objets (les abonnés) lorsqu’un événement se produit. L’éditeur n’a pas besoin de savoir qui écoute ou combien d’abonnés il y a. Les abonnés choisissent de s’inscrire.
Les événements sont basés sur des délégués. Un événement est un champ délégué avec des restrictions supplémentaires appliquées par le mot clé event : seul le code extérieur peut s’abonner (+=) ou se désabonner (-=) de l’événement ; seule la classe qui déclare l’événement peut l'invoquer (le déclencher).
La convention .NET pour les types délégués d’événements est System.EventHandler<TEventArgs>, où T est le type de données incluses dans la notification. Sa signature a toujours deux paramètres : l sender '(objet qui a déclenché l’événement) et les données d’événement de type T.
MessagePublisher publisher = new();
publisher.MessagePublished += (_, message) => Console.WriteLine($"Received: {message}");
publisher.Publish("Records updated");
Examiner le code :
-
MessagePublisherdéclareevent EventHandler<string>? MessagePublished. Le mot cléeventsignifie que les appelants peuvent seulement s’abonner ou se désabonner, mais ils ne peuvent pas l’appeler directement. -
publisher.MessagePublished += (_, message) => ...souscrit via une expression lambda. Le_rejette le paramètresendercar ce gestionnaire n’en a pas besoin. -
publisher.Publish("Records updated")déclenche l’événement et exécute chaque gestionnaire abonné.
L’abonnement est facultatif.
?.Invoke(...) dans la méthode Publish implique que l'événement se déclenche uniquement lorsqu'au moins un abonné est connecté. L’éditeur déclenche l’événement sans avoir connaissance ni se préoccuper de la présence d’éventuels auditeurs.