Expressions C # Lambda: Pourquoi devrais-je les utiliser?

J’ai rapidement lu la documentation Microsoft Lambda Expression .

Ce genre d’exemple m’a aidé à mieux comprendre, bien que:

delegate int del(int i); del myDelegate = x => x * x; int j = myDelegate(5); //j = 25 

Pourtant, je ne comprends pas pourquoi c’est une telle innovation. C’est juste une méthode qui meurt lorsque la “variable de méthode” se termine, non? Pourquoi devrais-je utiliser cela au lieu d’une vraie méthode?

Les expressions Lambda sont une syntaxe plus simple pour les delegates anonymes et peuvent être utilisées partout où un délégué anonyme peut être utilisé. Cependant, le contraire n’est pas vrai. Les expressions lambda peuvent être converties en arborescences d’expression, ce qui permet beaucoup de magie comme LINQ to SQL.

Voici un exemple d’une expression LINQ to Objects utilisant des delegates anonymes puis des expressions lambda pour montrer à quel point ils sont plus faciles à regarder:

 // anonymous delegate var evens = Enumerable .Range(1, 100) .Where(delegate(int x) { return (x % 2) == 0; }) .ToList(); // lambda expression var evens = Enumerable .Range(1, 100) .Where(x => (x % 2) == 0) .ToList(); 

Les expressions lambda et les delegates anonymes ont un avantage sur l’écriture d’une fonction distincte: ils implémentent des fermetures qui peuvent vous permettre de passer d’un état local à la fonction sans append de parameters à la fonction ou créer des objects à usage unique.

Les arbres d’expression sont une nouvelle fonctionnalité très puissante de C # 3.0 qui permet à une API d’examiner la structure d’une expression au lieu d’obtenir simplement une référence à une méthode pouvant être exécutée. Une API doit simplement créer un paramètre de délégation dans un paramètre Expression et le compilateur générera un arbre d’expression à partir d’un lambda au lieu d’un délégué anonyme:

 void Example(Predicate aDelegate); 

appelé comme:

 Example(x => x > 5); 

devient:

 void Example(Expression> expressionTree); 

Ce dernier recevra une représentation de l’ arbre de syntaxe abstraite décrivant l’expression x > 5 . LINQ to SQL repose sur ce comportement pour pouvoir convertir les expressions C # en expressions SQL souhaitées pour le filtrage / classement / etc. du côté serveur.

Les fonctions et expressions anonymes sont utiles pour les méthodes uniques qui ne bénéficient pas du travail supplémentaire requirejs pour créer une méthode complète.

Considérez cet exemple:

  ssortingng person = people.Find(person => person.Contains("Joe")); 

contre

  public ssortingng FindPerson(ssortingng nameContains, List persons) { foreach (ssortingng person in persons) if (person.Contains(nameContains)) return person; return null; } 

Celles-ci sont fonctionnellement équivalentes.

Je les ai trouvés utiles dans une situation où je voulais déclarer un gestionnaire pour un événement de contrôle, en utilisant un autre contrôle. Pour ce faire, vous devez normalement stocker les références des contrôles dans les champs de la classe afin de pouvoir les utiliser selon une méthode différente de celle qui a été créée.

 private ComboBox combo; private Label label; public CreateControls() { combo = new ComboBox(); label = new Label(); //some initializing code combo.SelectedIndexChanged += new EventHandler(combo_SelectedIndexChanged); } void combo_SelectedIndexChanged(object sender, EventArgs e) { label.Text = combo.SelectedValue; } 

Grâce aux expressions lambda, vous pouvez l’utiliser comme ceci:

 public CreateControls() { ComboBox combo = new ComboBox(); Label label = new Label(); //some initializing code combo.SelectedIndexChanged += (s, e) => {label.Text = combo.SelectedValue;}; } 

Beaucoup plus facile.

Lambda a nettoyé la syntaxe de délégué anonyme de C # 2.0 … par exemple

 Ssortingngs.Find(s => s == "hello"); 

A été fait dans C # 2.0 comme ceci:

 Ssortingngs.Find(delegate(Ssortingng s) { return s == "hello"; }); 

Fonctionnellement, ils font exactement la même chose, c’est juste une syntaxe beaucoup plus concise.

Ceci est juste une façon d’utiliser une expression lambda. Vous pouvez utiliser une expression lambda partout où vous pouvez utiliser un délégué. Cela vous permet de faire des choses comme ceci:

 List ssortingngs = new List(); ssortingngs.Add("Good"); ssortingngs.Add("Morning") ssortingngs.Add("Starshine"); ssortingngs.Add("The"); ssortingngs.Add("Earth"); ssortingngs.Add("says"); ssortingngs.Add("hello"); ssortingngs.Find(s => s == "hello"); 

Ce code recherche dans la liste une entrée correspondant au mot “hello”. L’autre façon de faire est de passer un délégué à la méthode Find, comme ceci:

 List ssortingngs = new List(); ssortingngs.Add("Good"); ssortingngs.Add("Morning") ssortingngs.Add("Starshine"); ssortingngs.Add("The"); ssortingngs.Add("Earth"); ssortingngs.Add("says"); ssortingngs.Add("hello"); private static bool FindHello(Ssortingng s) { return s == "hello"; } ssortingngs.Find(FindHello); 

EDIT :

Dans C # 2.0, cela pourrait être fait en utilisant la syntaxe de délégué anonyme:

  ssortingngs.Find(delegate(Ssortingng s) { return s == "hello"; }); 

Lambda a significativement nettoyé cette syntaxe.

Microsoft nous a donné un moyen plus propre et plus pratique de créer des delegates anonymes appelés expressions Lambda. Cependant, la partie expressions de cette déclaration ne fait pas l’object d’une grande attention. Microsoft a publié un espace de noms complet, System.Linq.Expressions , qui contient des classes permettant de créer des arborescences d’expression basées sur des expressions lambda. Les arbres d’expression sont constitués d’objects qui représentent la logique. Par exemple, x = y + z est une expression pouvant faire partie d’un arbre d’expression dans .Net. Prenons l’exemple suivant (simple):

 using System; using System.Linq; using System.Linq.Expressions; namespace ExpressionTreeThingy { class Program { static void Main(ssortingng[] args) { Expression> expr = (x) => x + 1; //this is not a delegate, but an object var del = expr.Comstack(); //comstacks the object to a CLR delegate, at runtime Console.WriteLine(del(5)); //we are just invoking a delegate at this point Console.ReadKey(); } } } 

Cet exemple est sortingvial. Et je suis sûr que vous pensez: «Ceci est inutile car j’aurais pu créer directement le délégué au lieu de créer une expression et de la comstackr à l’exécution». Et tu aurais raison. Mais cela fournit la base pour les arbres d’expression. Un certain nombre d’expressions sont disponibles dans les espaces de noms Expressions, et vous pouvez créer vos propres expressions. Je pense que vous pouvez voir que cela pourrait être utile lorsque vous ne savez pas exactement quel algorithme devrait être au moment de la conception ou de la compilation. J’ai vu un exemple quelque part pour l’utiliser pour écrire une calculasortingce scientifique. Vous pouvez également l’utiliser pour les systèmes bayésiens ou pour la programmation génétique (IA). Quelques fois au cours de ma carrière, j’ai dû écrire des fonctionnalités de type Excel qui permettaient aux utilisateurs de saisir des expressions simples (ajouts, soustractions, etc.) pour fonctionner avec les données disponibles. Dans pre-.Net 3.5, j’ai dû utiliser un langage de script externe à C # ou utiliser la fonctionnalité d’émission de code en reflection pour créer du code .Net à la volée. Maintenant, j’utiliserais des arbres d’expression.

Cela évite d’avoir à définir des méthodes qui ne sont utilisées qu’une seule fois dans un lieu spécifique, loin de l’endroit où elles sont utilisées. Les bons usages sont des comparateurs d’algorithmes génériques tels que le sorting, où vous pouvez ensuite définir une fonction de sorting personnalisée dans laquelle vous invoquez le sorting plutôt que de vous éloigner, vous obligeant à chercher ailleurs pour voir ce que vous sortingez.

Et ce n’est pas vraiment une innovation. Le LISP a des fonctions lambda depuis environ 30 ans ou plus.

Une expression lambda est comme une méthode anonyme écrite à la place d’une instance de délégué.

 delegate int MyDelagate (int i); MyDelagate delSquareFunction = x => x * x; 

Considérons l’expression lambda x => x * x;

La valeur du paramètre d’entrée est x (à gauche de =>)

La logique de la fonction est x * x (à droite de =>)

Le code d’une expression lambda peut être un bloc d’instructions au lieu d’une expression.

 x => {return x * x;}; 

Exemple

Remarque: Func est un délégué générique prédéfini.

  Console.WriteLine(MyMethod(x => "Hi " + x)); public static ssortingng MyMethod(Func strategy) { return strategy("Lijo").ToSsortingng(); } 

Les références

  1. Comment un délégué et une interface peuvent-ils être utilisés de manière interchangeable?

Vous pouvez également trouver l’utilisation des expressions lambda dans l’écriture de codes génériques pour agir sur vos méthodes.

Par exemple: Fonction générique pour calculer le temps pris par un appel de méthode. (c.-à-d. Action ici)

 public static long Measure(Action action) { Stopwatch sw = new Stopwatch(); sw.Start(); action(); sw.Stop(); return sw.ElapsedMilliseconds; } 

Et vous pouvez appeler la méthode ci-dessus en utilisant l’expression lambda comme suit,

 var timeTaken = Measure(() => yourMethod(param)); 

Expression vous permet d’obtenir la valeur de retour de votre méthode et de param

 var timeTaken = Measure(() => returnValue = yourMethod(param, out outParam)); 

La plupart du temps, vous n’utilisez que la fonctionnalité au même endroit.

L’expression lambda est un moyen concis de représenter une méthode anonyme. Les méthodes anonymes et les expressions Lambda vous permettent de définir la mise en œuvre de la méthode en ligne. Cependant, une méthode anonyme requirejs explicitement que vous définissiez les types de paramètre et le type de retour pour une méthode. L’expression Lambda utilise la fonctionnalité d’inférence de type de C # 3.0 qui permet au compilateur d’inférer le type de la variable en fonction du contexte. C’est très pratique car cela nous évite beaucoup de frappe!

C’est une façon de prendre de petites opérations et de les placer très près de l’endroit où elles sont utilisées (ce qui n’est pas sans rappeler de déclarer une variable proche de son point d’utilisation). Ceci est censé rendre votre code plus lisible. En anonymisant l’expression, il est également beaucoup plus difficile pour une personne de briser votre code client si la fonction est utilisée ailleurs et modifiée pour “l’améliorer”.

De même, pourquoi devez-vous utiliser foreach? Vous pouvez tout faire dans foreach avec une plaine pour la boucle ou simplement utiliser directement IEnumerable. Réponse: vous n’en avez pas besoin mais cela rend votre code plus lisible.

L’innovation réside dans le type de sécurité et de transparence. Bien que vous ne déclariez pas les types d’expressions lambda, ils sont déduits et peuvent être utilisés par la recherche de code, l’parsing statique, les outils de refactoring et la reflection à l’exécution.

Par exemple, avant que vous n’ayez pu utiliser SQL et recevoir une attaque par injection SQL, car un pirate a transmis une chaîne où un nombre était normalement attendu. Maintenant, vous utiliseriez une expression lambda LINQ, qui est protégée contre cela.

La construction d’une API LINQ sur des delegates purs n’est pas possible, car elle nécessite de combiner des arborescences d’expression avant de les évaluer.

En 2016, la plupart des langages populaires sont compatibles avec l’ expression lambda et C # était l’un des pionniers de cette évolution parmi les langages impératifs les plus répandus.

Ce sont peut-être les meilleures explications sur l’utilisation des expressions lambda -> https://youtu.be/j9nj5dTo54Q

En résumé, il s’agit d’améliorer la lisibilité du code, de réduire les risques d’erreurs en réutilisant plutôt que de répliquer le code, et de tirer parti de l’optimisation qui se produit en coulisse.