问题描述
在寻求了解看起来很奇怪的'=>'运算符时,我发现了一个不错的,作者非常简洁明了:
有人在理解lambda的基础上有任何提示吗?
例如:如果我得到类似的信息(来自):
filenames.SelectMany(f =>
Assembly.LoadFrom(f).GetCustomAttributes(typeof(PluginClassAttribute),true)
.Cast< PluginClassAttribute>()
.Select(a => a.PluginType)
).ToList();
如何将其分解为更简单的部分?
更新:想炫耀我的第一个lambda表达式。不要嘲笑我,但是我没有复制别人的例子就这样做了……而且它第一次起作用:
public ModuleData [] GetStartModules()
{返回modules.FindAll(start => start.IsBatch == true).ToArray(); }
我们来剖析您的代码示例:
文件名.SelectMany(f =>
Assembly.LoadFrom(f).GetCustomAttributes(typeof(PluginClassAttribute),true)
.Cast< PluginClassAttribute>()
.Select(a => a.PluginType)
).ToList();
因此,我们从 string [] $ c $开始c>称为
文件名
。我们在数组上调用 SelectMany
扩展方法,然后在结果上调用 ToList
:
文件名.SelectMany(
...
).ToList();
SelectMany
以委托作为参数,在在这种情况下,委托人必须采用类型为 string
的一个参数作为输入,并返回 IEnumerable< T>
(其中推断出 T
的类型)。这是lambda进入阶段的地方:
文件名.SelectMany(f =>
Assembly.LoadFrom(f) .GetCustomAttributes(typeof(PluginClassAttribute),true)
).ToList()
将会这是因为对于文件名
数组中的每个元素,都会调用委托。 f
是输入参数, =>
右边的内容是委托引用的方法主体至。在这种情况下,将为数组中的文件名调用 Assembly.LoadFrom
,使用以下命令将文件名传递给 LoadFrom
方法 f
参数。在返回的 AssemblyInstance
上,将调用 GetCustomAttributes(typeof(PluginClassAttribute),true)
,它返回一个数组 Attribute
实例的数量。因此,编译器无法推断前面提到的 T
的类型是 Assembly
。
在返回的 IEnumerable< Attribute<
上, Cast< PluginClassAttribute>()
被调用,返回 IEnumerable< PluginClassAttribute>
。
所以我们现在有了 IEnumerable< ; PluginClassAttribute>
,然后在其上调用 Select
。 Select
方法类似于 SelectMany
,但是返回单个类型为 T 的实例。 code>(由编译器推断),而不是
IEnumerable< T>
。设置是相同的;对于 IEnumerable< PluginClassAttribute>
中的每个元素,它将调用已定义的委托,并将当前元素值传递给它:
.Select(a => a.PluginType)
a 是输入参数, a.PluginType
是方法主体。因此,对于列表中的每个 PluginClassAttribute
实例,它将返回 PluginType
属性的值(我假设属性的类型为 Type
)。
执行摘要
如果我们将那些零碎的部分粘合在一起:
//处理文件名数组
文件名中的所有字符串。 SelectMany(f =>
//从具有给定文件名
//的程序集
//中获取类型为PluginClassAttribute的所有Attributes。 ,true)
//将返回的实例转换为PluginClassAttribute
.Cast< PluginClassAttribute>()
//从每个PluginClassAttribute实例
中返回PluginType属性.Select(a => ; a.PluginType)
).ToList();
Lambdas与代理人
让我们通过比较lambda和委托来完成这一点。采取以下列表:
List< string>字符串=新列表< string> { 一二三 };
说我们要过滤掉以字母 t开头的内容:
var result = strings.Where(s => s.StartsWith( t));
这是最常见的方法;使用lambda表达式进行设置。但是还有其他选择:
Func< string,bool> func = proxy(string s){return s.StartsWith( t);};
结果=字符串。
这基本上是相同的:首先,我们创建一个类型为的委托Func< string,bool>
(这意味着它将 string
作为输入参数,并返回 bool
)。然后,将该委托作为参数传递给 Where
方法。这是编译器在第一个示例( strings.Where(s => s.StartsWith( t));
)的幕后为我们做的。 / p>
第三种选择是简单地将委托传递给非匿名方法:
private bool StringsStartingWithT(string s)
{
return s.StartsWith( t);
}
//代码中的其他地方:
result = strings.Where(StringsStartingWithT);
因此,在我们看这里的情况下,lambda表达式是一种相当紧凑的方法
如果您有足够的精力在这里读完,那么,谢谢您的时间:)
In my quest to understand the very odd looking ' => ' operator, I have found a good place to start, and the author is very concise and clear:
Does anyone have any tips on understanding the basics of lambdas so that it becomes easier to 'decipher' the more complex lambda statements?
For instance: if I am given something like (from an answer I received here):
filenames.SelectMany(f =>
Assembly.LoadFrom(f).GetCustomAttributes(typeof(PluginClassAttribute), true)
.Cast<PluginClassAttribute>()
.Select(a => a.PluginType)
).ToList();
How can I go about breaking this down into more simple pieces?
UPDATE: wanted to show off my first lambda expression. Don't laugh at me, but I did it without copying someone's example...and it worked the first time:
public ModuleData[] GetStartModules( )
{ return modules.FindAll(start => start.IsBatch == true).ToArray(); }
Let's dissect your code sample:
filenames.SelectMany(f =>
Assembly.LoadFrom(f).GetCustomAttributes(typeof(PluginClassAttribute), true)
.Cast<PluginClassAttribute>()
.Select(a => a.PluginType)
).ToList();
So, we start off with a string[]
called filenames
. We invoke the SelectMany
extension method on the array, and then we invoke ToList
on the result:
filenames.SelectMany(
...
).ToList();
SelectMany
takes a delegate as parameter, in this case the delegate must take one parameter of the type string
as input, and return an IEnumerable<T>
(Where the type of T
is inferred). This is where lambdas enter the stage:
filenames.SelectMany(f =>
Assembly.LoadFrom(f).GetCustomAttributes(typeof(PluginClassAttribute), true)
).ToList()
What will happen here is that for each element in the filenames
array, the delegate will be invoked. f
is the input parameter, and whatever comes to the right of =>
is the method body that the delegate refers to. In this case, Assembly.LoadFrom
will be invoked for filename in the array, passing he filename into the LoadFrom
method using the f
argument. On the AssemblyInstance
that is returned, GetCustomAttributes(typeof(PluginClassAttribute), true)
will be invoked, which returns an array of Attribute
instances. So the compiler can not infer that the type of T
mentioned earlier is Assembly
.
On the IEnumerable<Attribute>
that is returned, Cast<PluginClassAttribute>()
will be invoked, returning an IEnumerable<PluginClassAttribute>
.
So now we have an IEnumerable<PluginClassAttribute>
, and we invoke Select
on it. The Select
method is similar to SelectMany
, but returns a single instance of type T
(which is inferred by the compiler) instead of an IEnumerable<T>
. The setup is identical; for each element in the IEnumerable<PluginClassAttribute>
it will invoke the defined delegate, passing the current element value into it:
.Select(a => a.PluginType)
Again, a
is the input parameter, a.PluginType
is the method body. So, for each PluginClassAttribute
instance in the list, it will return the value of the PluginType
property (I will assume this property is of the type Type
).
Executive Summary
If we glue those bits and pieces together:
// 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();
Lambdas vs. Delegates
Let's finish this off by comparing lambdas to delegates. Take the following list:
List<string> strings = new List<string> { "one", "two", "three" };
Say we want to filter out those that starts with the letter "t":
var result = strings.Where(s => s.StartsWith("t"));
This is the most common approach; set it up using a lambda expression. But there are alternatives:
Func<string,bool> func = delegate(string s) { return s.StartsWith("t");};
result = strings.Where(func);
This is essentially the same thing: first we create a delegate of the type Func<string, bool>
(that means that it takes a string
as input parameter, and returns a bool
). Then we pass that delegate as parameter to the Where
method. This is what the compiler did for us behind the scenes in the first sample (strings.Where(s => s.StartsWith("t"));
).
One third option is to simply pass a delegate to a non-anonymous method:
private bool StringsStartingWithT(string s)
{
return s.StartsWith("t");
}
// somewhere else in the code:
result = strings.Where(StringsStartingWithT);
So, in the case that we are looking at here, the lambda expression is a rather compact way of defining a delegate, typically referring an anonymous method.
And if you had the energy read all the way here, well, thanks for your time :)
这篇关于Lambda for Dummies ....任何人,有人吗?我觉得不是的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!