web-dev-qa-db-fra.com

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

J'ai rapidement lu la Microsoft Lambda Expression documentation.

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

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 quand la "variable de méthode" se termine, non? Pourquoi devrais-je utiliser ceci au lieu d'une vraie méthode?

290

Les expressions Lambda sont une syntaxe plus simple pour les délégués 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 arbres d’expression, ce qui permet beaucoup de magie comme LINQ to SQL. 

Voici un exemple d'expression LINQ to Objects utilisant des délégués anonymes, puis des expressions lambda, pour montrer à quel point elles 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 délégués anonymes présentent un avantage par rapport à l'écriture d'une fonction distincte: ils implémentent closures , ce qui peut vous permettre de passer l'état local à la fonction sans ajouter de paramètres à la fonction ni créer d'objets à 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 de simplement obtenir une référence à une méthode pouvant être exécutée. Une API doit simplement transformer un paramètre délégué en paramètre Expression<T> et le compilateur générera une arborescence d'expression à partir d'un lambda au lieu d'un délégué anonyme:

void Example(Predicate<int> aDelegate);

appelé comme:

Example(x => x > 5);

devient:

void Example(Expression<Predicate<int>> expressionTree);

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

270
Neil Williams

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

Considérons cet exemple:

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

versus

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

Ce sont fonctionnellement équivalents.

133
Joseph Daigle

Je les ai trouvé utiles dans une situation où je voulais déclarer un gestionnaire pour un événement de contrôle, en utilisant un autre contrôle . 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.

83
agnieszka

Lambda a épuré la syntaxe de délégué anonyme du C # 2.0 ... par exemple

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

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

Strings.Find(delegate(String s) { return s == "hello"; });

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

35
FlySwat

Ce n'est qu'une façon d'utiliser une expression lambda. Vous pouvez utiliser une expression lambda n'importe où vous pouvez utiliser un délégué. Cela vous permet de faire des choses comme ceci:

List<string> strings = new List<string>();
strings.Add("Good");
strings.Add("Morning")
strings.Add("Starshine");
strings.Add("The");
strings.Add("Earth");
strings.Add("says");
strings.Add("hello");

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

Ce code va rechercher dans la liste une entrée qui correspond au mot "hello". L'autre façon de faire est de passer un délégué à la méthode Find, comme ceci:

List<string> strings = new List<string>();
strings.Add("Good");
strings.Add("Morning")
strings.Add("Starshine");
strings.Add("The");
strings.Add("Earth");
strings.Add("says");
strings.Add("hello");

private static bool FindHello(String s)
{
    return s == "hello";
}

strings.Find(FindHello);

MODIFIER:

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

  strings.Find(delegate(String s) { return s == "hello"; });

Lambda a considérablement nettoyé cette syntaxe.

29
Scott Dorman

Microsoft nous a fourni un moyen plus simple et plus pratique de créer des délégués anonymes appelés expressions Lambda. Cependant, peu d'attention est accordée à la partie expressions de cette déclaration. Microsoft a publié un espace de noms complet, System.Linq.Expressions , qui contient des classes permettant de créer des arbres d'expression basés sur des expressions lambda. Les arbres d'expression sont constitués d'objets représentant la logique. Par exemple, x = y + z est une expression pouvant faire partie d'un arbre d'expression en .Net. Prenons l'exemple (simple) suivant:

using System;
using System.Linq;
using System.Linq.Expressions;


namespace ExpressionTreeThingy
{
    class Program
    {
        static void Main(string[] args)
        {
            Expression<Func<int, int>> expr = (x) => x + 1; //this is not a delegate, but an object
            var del = expr.Compile(); //compiles 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 trivial. Et je suis sûr que vous pensez: "Ceci est inutile car j'aurais pu directement créer le délégué au lieu de créer une expression et de la compiler au moment de 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 votre propre expression. Je pense que vous pouvez voir que cela pourrait être utile si vous ne savez pas exactement ce que l'algorithme devrait être au moment de la conception ou de la compilation. J'ai vu un exemple quelque part pour utiliser ceci pour écrire une calculatrice scientifique. Vous pouvez également l'utiliser pour les systèmes { bayésiens }, ou pour la { programmation génétique } _ (AI). Quelques fois dans ma carrière, j'ai dû écrire des fonctionnalités similaires à celles d'Excel permettant aux utilisateurs de saisir des expressions simples (addition, soustrations, etc.) pour exploiter les données disponibles. Dans pre -.Net 3.5, je devais recourir à un langage de script externe à C # ou utiliser la fonctionnalité d’émission de code en réflexion pour créer du code .Net à la volée. Maintenant, je voudrais utiliser des arbres d'expression. 

21
Jason Jackson

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 bonnes utilisations sont comme des comparateurs pour des algorithmes génériques tels que le tri, où vous pouvez ensuite définir une fonction de tri personnalisée dans laquelle vous appelez le tri plutôt que de vous éloigner, vous obligeant à regarder ailleurs pour voir sur quoi vous triez.

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

12
workmad3

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 string MyMethod(Func<string, string> strategy)
    {
        return strategy("Lijo").ToString();
    }

Références

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

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'est-à-dire 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 une valeur de retour de votre méthode et de votre paramètre param

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

Souvent, vous n'utilisez la fonctionnalité qu'à un seul endroit, ce qui rend une méthode encombrante.

4
Darren Kopp

L'expression Lambda est un moyen concis de représenter une méthode anonyme. Les méthodes anonymes et les expressions Lambda vous permettent toutes deux de définir l'implémentation de la méthode en ligne. Toutefois, une méthode anonyme nécessite explicitement de définir les types de paramètre et le type de retour d'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 dactylographie!

4
Vijesh VP

C'est une façon de prendre une petite opération et de la placer très près de l'endroit où elle est utilisée (ce qui n'est pas très différent de la déclaration d'une variable proche de son point d'utilisation). Ceci est supposé rendre votre code plus lisible. En anonymisant l'expression, vous empêchez beaucoup plus facilement quelqu'un de casser votre code client si la fonction est utilisée ailleurs et modifiée pour "l'améliorer".

De même, pourquoi avez-vous besoin d'utiliser foreach? Vous pouvez tout faire pour chaque recherche avec une boucle de type ou simplement en utilisant IEnumerable directement. Réponse: vous n’avez pas besoin mais cela rend votre code plus lisible.

3
plinth

C’est peut-être les meilleures explications sur les raisons pour lesquelles les expressions lambda sont utilisées -> 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 reproduire le code, et de tirer parti de l'optimisation réalisée en coulisse. 

0
coffeeeee

L'innovation est dans le type sécurité et 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'analyse statique, les outils de refactoring et la réflexion à l'exécution.

Par exemple, auparavant, vous avez peut-être utilisé SQL et risqué de subir une attaque par injection SQL, car un pirate informatique a transmis une chaîne contenant normalement un nombre. Maintenant, vous utiliseriez une expression LINQ lambda, qui en est protégée.

Construire une API LINQ sur des délégués purs n'est pas possible, car cela nécessite de combiner des arbres d'expression avant de les évaluer.

En 2016, la plupart des langues populaires ont expression lambda support, et C # a été l'un des pionniers de cette évolution parmi les langues impératives traditionnelles.

0
battlmonstr