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 :)