36 votes

Lambda for Dummies .... n'importe qui, n'importe qui? Je crois que non

Dans ma quête pour comprendre la très étrange à la recherche '=> ' opérateur, j'ai trouvé un bon endroit pour commencer, et l'auteur est très concis et clair:

parameters => expression

Quelqu'un aurait-il des conseils sur la compréhension des notions de base de la lambdas de sorte qu'il devient plus facile à "déchiffrer" le plus complexe lambda déclarations?

Par exemple: si j'obtiens quelque chose comme (à partir d'une réponse que j'ai reçue ici):

filenames.SelectMany(f => 
        Assembly.LoadFrom(f).GetCustomAttributes(typeof(PluginClassAttribute), true)
        .Cast<PluginClassAttribute>()
        .Select(a => a.PluginType)
).ToList();

Comment puis-je faire en plus simple de morceaux?


Mise à JOUR: envie de montrer ma première expression lambda. Ne vous moquez pas de moi, mais je l'ai fait sans copier l'exemple de quelqu'un...et cela a fonctionné la première fois:

public ModuleData[] GetStartModules( )
{ return modules.FindAll(start => start.IsBatch == true).ToArray(); }

Je sais que c'est ringard-simple, mais j'ai été fier de l'être. Et je voulais vous remercier à nouveau pour le grand explications!!!

40voto

Fredrik Mörk Points 85694

Nous allons disséquer l'exemple de code:

filenames.SelectMany(f => 
        Assembly.LoadFrom(f).GetCustomAttributes(typeof(PluginClassAttribute), true)
        .Cast<PluginClassAttribute>()
        .Select(a => a.PluginType)
).ToList();

Donc, nous commençons avec un string[] appelés filenames. Nous invoquons l' SelectMany méthode d'extension sur le tableau, puis nous invoquons ToList sur le résultat:

filenames.SelectMany(
   ...
).ToList();

SelectMany prend un délégué en tant que paramètre, dans ce cas, le délégué doit prendre un paramètre de type string en entrée et retourne un IEnumerable<T> (Lorsque le type d' T est déduite). C'est là que les lambdas entrer dans le stade:

filenames.SelectMany(f => 
        Assembly.LoadFrom(f).GetCustomAttributes(typeof(PluginClassAttribute), true)
).ToList()

Ce qui va se passer ici, c'est que pour chaque élément dans l' filenames tableau, le délégué sera invoquée. f est le paramètre d'entrée, et tout ce qui vient à la droite de l' => est le corps de la méthode que le délégué se réfère. Dans ce cas, Assembly.LoadFrom sera invoquée pour le nom de fichier dans le tableau, en passant il nom de fichier dans l' LoadFrom méthode à l'aide de l' f argument. Sur l' AssemblyInstance qui est renvoyée, GetCustomAttributes(typeof(PluginClassAttribute), true) sera invoquée, qui retourne un tableau d' Attribute des cas. Ainsi, le compilateur ne peut pas en déduire que le type d' T précédemment mentionné, est Assembly.

Sur l' IEnumerable<Attribute> qui est renvoyée, Cast<PluginClassAttribute>() sera invoqué, au retour d'une IEnumerable<PluginClassAttribute>.

Alors maintenant, nous avons une IEnumerable<PluginClassAttribute>, et nous invoquons Select sur il. L' Select méthode est similaire à l' SelectMany, mais retourne une instance unique de type T (ce qui est déduit par le compilateur) au lieu d'une IEnumerable<T>. La configuration est identique; pour chaque élément de la IEnumerable<PluginClassAttribute> il invoquera l'défini délégué, en passant l'élément courant de la valeur en elle:

.Select(a => a.PluginType)

Encore une fois, a est le paramètre d'entrée, a.PluginType est le corps de la méthode. Ainsi, pour chaque PluginClassAttribute instance dans la liste, il sera de retour la valeur de l' PluginType bien (je vais supposer cette propriété est de type Type).

Résumé
Si on colle les morceaux ensemble:

// process all strings in the filenames array
filenames.SelectMany(f => 
        // get all Attributes of the type PluginClassAttribute from the assembly
        // with the given file name
        Assembly.LoadFrom(f).GetCustomAttributes(typeof(PluginClassAttribute), true)
        // cast the returned instances to PluginClassAttribute
        .Cast<PluginClassAttribute>()
        // return the PluginType property from each PluginClassAttribute instance
        .Select(a => a.PluginType)
).ToList();

Les Lambdas vs Délégués
Nous allons terminer ce en comparant les lambdas, pour les délégués. Prendre la liste suivante:

List<string> strings = new List<string> { "one", "two", "three" };

Disons que nous voulons filtrer ceux qui commence par la lettre "t":

var result = strings.Where(s => s.StartsWith("t"));

C'est l'approche la plus commune; le configurer à l'aide d'une expression lambda. Mais il existe des alternatives:

Func<string,bool> func = delegate(string s) { return s.StartsWith("t");};
result = strings.Where(func);

C'est essentiellement la même chose: d'abord, nous créons un délégué de type Func<string, bool> (ce qui signifie qu'il prend un string comme paramètre en entrée et renvoie un bool). Ensuite on passe au délégué en tant que paramètre à la Where méthode. C'est ce que le compilateur a fait pour nous dans les coulisses du premier échantillon (strings.Where(s => s.StartsWith("t"));).

Une troisième option est de simplement passer un délégué à une non-méthode anonyme:

private bool StringsStartingWithT(string s)
{
    return s.StartsWith("t");
}

// somewhere else in the code:
result = strings.Where(StringsStartingWithT);

Ainsi, dans le cas qui nous intéressent ici, l'expression lambda est plutôt une façon compacte de la définition d'un délégué, généralement en se référant d'une méthode anonyme.

Et si vous avez eu l'énergie de lire tout le chemin ici, et bien, merci pour votre temps :)

6voto

kastermester Points 1840

Donc, pour commencer avec le plus effrayant définition de la lambda est une autre manière de définir une méthode anonyme. Il y a (depuis C# 2.0 je crois) un moyen de construire des méthodes anonymes - cependant que la syntaxe était très... inconvinient.

Quel est donc une méthode anonyme? C'est une façon de définir une méthode inline, avec pas de nom, donc étant anonyme. Ceci est utile si vous avez une méthode qui prend un délégué, que vous pouvez passer cette expression lambda / méthode anonyme en tant que paramètre, étant donné que les types correspondent. Prendre IEnumerable.Sélectionnez par exemple, il est défini comme suit:

IEnumerable<TResult> Select<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, TResult> selector);

Si vous utilisez cette méthode normalement à dire une Liste et sélectionnez chaque élément deux fois (c'est concaténé à lui-même):

string MyConcat(string str){
    return str + str;
}

...

void myMethod(){
    IEnumerable<string> result = someIEnumerable.Select(MyConcat);
}

C'est un très inconvinient façon de faire cela, surtout si vous souhaitez effectuer un grand nombre de ces opérations aussi généralement ces types de méthodes que vous utilisez seulement une fois. La définition que vous avez montré (paramètres => expression) est très concise et il frappe sur place. La chose intéressante à propos de lambda, c'est que vous n'avez pas besoin d'exprimer le type des paramètres - aussi longtemps qu'ils l'on peut inférer à partir de l'expression. C'est à dire. dans Sélectionnez celui - ci, nous savons que le premier paramètre doit être de type TSource - parce que la définition d'une méthode précise. De plus - si nous appelons la méthode comme foo.Sélectionnez(...) alors la valeur de retour de l'expression de définir TResult.

Une chose intéressante est que pour une déclaration de lambda est le mot-clé return n'est pas nécessaire - le lambda sera de retour tout ce qu'une expression. Toutefois, si vous utilisez un bloc (enveloppé dans '{' et'}'), alors vous devez inclure le mot-clé return, comme d'habitude.

Si l'on veut, c'est toujours 100% légal pour définir les types des paramètres. Avec ces nouvelles connaissances, nous allons essayer et de réécriture de l'exemple précédent:

void myMethod(){
    IEnumerable<string> result = someIEnumerable.Select(s => s + s);
}

Ou, de manière explicite paramètres

void myMethod(){
    IEnumerable<string> result = someIEnumerable.Select((string s) => s + s);
}

Une autre caractéristique intéressante de lambda en C# est leur utilisation pour construire des arbres d'expression. Ce n'est probablement pas "débutant" matériel bien - mais en bref une expression de l'arbre contient toutes les méta-données sur un lambda, plutôt que le code exécutable.

5voto

Mario Fernandez Points 8974

Eh bien, vous pouvez voir un lambda comme un moyen rapide d'écrire une méthode que vous souhaitez utiliser uniquement une fois. Par exemple, la méthode suivante

private int sum5(int n)
{
    return n + 5;
}

est l'équivalent de la lambda: (n) => n + 5 . Sauf que vous pouvez appeler la méthode de n'importe où dans votre classe, et le lambda ne vit que dans le champ d'application elle est déclarée (Vous pouvez également stocker des lambdas dans l'Action et la touche Func objets)

Autre chose que les lambdas peut faire pour vous est de saisir la portée, la construction d'une clôture. Par exemple, si vous avez quelque chose comme ceci:

...methodbody
int acc = 5;
Func<int> addAcc = (n) => n + acc;

Ce que vous avez là est une fonction qui accepte un argument comme avant, mais la quantité ajoutée est prise à partir de la valeur de la variable. Le lambda peut vivre, même après le champ d'application dans lequel l'acc a été défini est fini.

Vous pouvez construire de très belles choses avec des lambdas, mais vous devez être prudent, parce que parfois vous perdre de la lisibilité avec des trucs comme ça.

2voto

TJB Points 7536

Cette simple vidéo sur TekPub est une bonne explication simple destinée aux développeurs qui sont firmiliar avec le codage mais pas avec lambdas.

TekPub - Concepts: # 2 Lambdas

Vous avez évidemment beaucoup de retours ici, mais c’est une autre bonne source et une explication simple.

2voto

VoidPointer Points 7260

Comme d'autres l'ont dit, une expression lambda est une notation pour une fonction. Il lie les variables libres dans le côté droit de l'expression des paramètres sur la gauche.

a => a + 1

crée une fonction qui lie la variable indépendante de la un dans l'expression (a + 1) pour le premier paramètre de la fonction et retourne cette fonction.

Un cas où les Lambdas sont extrêmement utiles lorsque vous les utilisez pour travailler avec des structures de listes. Le Système.Linq.Énumérable classe fournit beaucoup de fonctions utiles qui vous permettent de travailler avec les expressions Lambda et les objets implémentant IEnumerable. Par exemple Énumérable.Où peut être utilisé pour filtrer une liste:

List<string> fruits = new List<string> { 
        "apple", "passionfruit", "banana", "mango", 
        "orange", "blueberry", "grape", "strawberry" };

IEnumerable<string> shortFruits = fruits.Where(fruit => fruit.Length < 6);

foreach (string fruit in shortFruits) {
    Console.WriteLine(fruit);
}

La sortie sera "la pomme, la mangue, raisin".

Essayez de comprendre ce qui se passe ici: l'expression de fruits => fruit.Longueur < 6 crée une fonction qui renvoie true si le paramètre de la Longueur de la propriété est à moins de 6.

Énumérable.Où les boucles sur la Liste et crée une nouvelle Liste qui ne contient que les éléments pour lesquels l'fournis fonction renvoie la valeur true. Cela vous évite d'écrire du code qui itère sur la Liste, vérifie la présence d'un prédicat pour chaque élément et fait quelque chose.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X