Lambda for Dummies...任何人,任何人?我认为不是
在我寻求理解看起来非常奇怪的 ' => ' 运算符,我找到了一个很好的 从哪里开始,作者非常简洁明了:
参数=>表达
有没有人有任何关于理解 lambda 基础知识的提示,以便更容易“破译”更复杂的 lambda 语句?
例如:如果我得到类似的东西(来自我在这里收到的答案):
filenames.SelectMany(f =>
Assembly.LoadFrom(f).GetCustomAttributes(typeof(PluginClassAttribute), true)
.Cast<PluginClassAttribute>()
.Select(a => a.PluginType)
).ToList();
我怎样才能把它分解成更简单的部分?
更新:想展示我的第一个 lambda 表达式。不要笑我,但我没有复制别人的例子就做到了……而且第一次就成功了:
public ModuleData[] GetStartModules( )
{ return modules.FindAll(start => start.IsBatch == true).ToArray(); }
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:
parameters => expression
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(); }
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(10)
让我们剖析您的代码示例:
因此,我们从一个名为
filenames
的string[]
开始。我们对数组调用SelectMany
扩展方法,然后对结果调用ToList
:在本例中,
SelectMany
采用委托作为参数委托必须采用string
类型的一个参数作为输入,并返回一个IEnumerable
(其中推断出T
的类型) 。这就是 lambda 登场的地方:这里将发生的是,对于
filenames
数组中的每个元素,都会调用委托。f
是输入参数,=>
右侧的内容是委托引用的方法体。在这种情况下,将针对数组中的文件名调用Assembly.LoadFrom
,并使用f
参数将文件名传递到LoadFrom
方法中。在返回的AssemblyInstance
上,将调用GetCustomAttributes(typeof(PluginClassAttribute), true)
,它返回Attribute
实例的数组。所以编译器无法推断出前面提到的T
的类型是Assembly
。在返回的
IEnumerable
上,将调用Cast()
,返回IEnumerable
。现在我们有了一个
IEnumerable
,我们对其调用Select
。Select
方法与SelectMany
类似,但返回类型T
的单个实例(由编译器推断),而不是>IEnumerable
。设置是相同的;对于IEnumerable
中的每个元素,它将调用定义的委托,将当前元素值传递给其中:同样,
a
是输入参数,a .PluginType
是方法主体。因此,对于列表中的每个PluginClassAttribute
实例,它将返回PluginType
属性的值(我假设该属性的类型为Type)。
执行摘要
如果我们将这些碎片粘合在一起:
Lambda 与委托
让我们通过比较 lambda 和委托来结束这一点。采取以下列表:
假设我们要过滤掉以字母“t”开头的那些:
这是最常见的方法;使用 lambda 表达式进行设置。但还有其他选择:
这本质上是同一件事:首先我们创建一个
Func
类型的委托(这意味着它需要一个string
作为输入参数,并返回一个bool
)。然后我们将该委托作为参数传递给Where
方法。这就是编译器在第一个示例中在幕后为我们所做的事情 (strings.Where(s => s.StartsWith("t"));
)。第三种选择是简单地将委托传递给非匿名方法:
因此,在我们在这里看到的情况下,lambda 表达式是定义委托的一种相当紧凑的方式,通常引用匿名方法。
如果您有精力读完这里,那么,谢谢您的宝贵时间:)
Let's dissect your code sample:
So, we start off with a
string[]
calledfilenames
. We invoke theSelectMany
extension method on the array, and then we invokeToList
on the result:SelectMany
takes a delegate as parameter, in this case the delegate must take one parameter of the typestring
as input, and return anIEnumerable<T>
(Where the type ofT
is inferred). This is where lambdas enter the stage: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 theLoadFrom
method using thef
argument. On theAssemblyInstance
that is returned,GetCustomAttributes(typeof(PluginClassAttribute), true)
will be invoked, which returns an array ofAttribute
instances. So the compiler can not infer that the type ofT
mentioned earlier isAssembly
.On the
IEnumerable<Attribute>
that is returned,Cast<PluginClassAttribute>()
will be invoked, returning anIEnumerable<PluginClassAttribute>
.So now we have an
IEnumerable<PluginClassAttribute>
, and we invokeSelect
on it. TheSelect
method is similar toSelectMany
, but returns a single instance of typeT
(which is inferred by the compiler) instead of anIEnumerable<T>
. The setup is identical; for each element in theIEnumerable<PluginClassAttribute>
it will invoke the defined delegate, passing the current element value into it:Again,
a
is the input parameter,a.PluginType
is the method body. So, for eachPluginClassAttribute
instance in the list, it will return the value of thePluginType
property (I will assume this property is of the typeType
).Executive Summary
If we glue those bits and pieces together:
Lambdas vs. Delegates
Let's finish this off by comparing lambdas to delegates. Take the following list:
Say we want to filter out those that starts with the letter "t":
This is the most common approach; set it up using a lambda expression. But there are alternatives:
This is essentially the same thing: first we create a delegate of the type
Func<string, bool>
(that means that it takes astring
as input parameter, and returns abool
). Then we pass that delegate as parameter to theWhere
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:
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 是定义匿名方法的另一种方式。 (我相信从 C# 2.0 开始)有一种构造匿名方法的方法 - 然而这种语法非常......不方便。
那么什么是匿名方法呢?这是一种定义内联方法的方法,没有名称 - 因此是匿名的。如果您有一个接受委托的方法,这非常有用,因为您可以将此 lambda 表达式/匿名方法作为参数传递(假设类型匹配)。以 IEnumerable.Select 为例,它的定义如下:
如果您通常在 List 上使用此方法并选择每个元素两次(即与其自身连接):
这是一种非常不方便的方法,尤其是如果您希望执行许多这样的操作 - 通常这些类型的方法您只使用一次。您显示的定义(参数 => 表达式)非常简洁并且恰到好处。 lambda 的有趣之处在于,您不需要表达参数的类型 - 只要可以从表达式中推断出它们即可。 IE。在 Select 的例子中 - 我们知道第一个参数必须是 TSource 类型 - 因为方法的定义是这样规定的。更进一步 - 如果我们像 foo.Select(...) 一样调用该方法,那么表达式的返回值将定义 TResult。
一件有趣的事情是,对于单语句 lambda 来说,不需要 return 关键字 - lambda 将返回一个表达式计算结果的任何内容。但是,如果您使用块(包含在“{”和“}”中),则必须像往常一样包含 return 关键字。
如果愿意的话,定义参数的类型仍然是 100% 合法的。有了这些新知识,让我们尝试重写前面的示例:
或者,使用明确的参数声明
C# 中 lambda 的另一个有趣功能是它们用于构造 表达式树。虽然这可能不是“初学者”材料 - 但简而言之,表达式树包含有关 lambda 的所有元数据,而不是可执行代码。
So, to start off with the scary definition - a lambda is another way of defining an anonymous method. There has (since C# 2.0 I believe) been a way to construct anonymous methods - however that syntax was very... inconvinient.
So what is an anonymous method? It is a way of defining a method inline, with no name - hence being anonymous. This is useful if you have a method that takes a delegate, as you can pass this lambda expression / anonymous method as a parameter, given that the types match up. Take IEnumerable.Select as an example, it is defined as follows:
If you were to use this method normally on say a List and select each element twice (that is concatenated to itself):
This is a very inconvinient way of doing this, especially if you wish to perform many of these operations - also typically these kinds of methods you only use once. The definition you showed (parameters => expression) is very consise and hits it spot on. The interesting thing about lambda is that you do not need to express the type of the parameters - as long as they can be infered from the expression. Ie. in Select's case - we know the first parameter must be of type TSource - because the definition of the method states so. Further more - if we call the method just as foo.Select(...) then the return value of the expression will define TResult.
An interesting thing as well is that for one-statement lambda's the return keyword is not needed - the lambda will return whatever that one expression evaluates to. However if you use a block (wrapped in '{' and '}') then you must include the return keyword like usual.
If one wishes to, it is still 100% legal to define the types of the parameters. With this new knowledge, let's try and rewrite the previous example:
Or, with explicit parameters stated
Another interesting feature of lambda's in C# is their use to construct expression trees. That is probably not "beginner" material though - but in short an expression tree contains all the meta data about a lambda, rather than executable code.
好吧,您可以将 lambda 视为编写只想使用一次的方法的快速方法。例如,以下方法
等效于 lambda:
(n) => n + 5 。除了您可以在类中的任何位置调用该方法,并且 lambda 仅存在于它声明的范围内(您还可以将 lambda 存储在 Action 和 Func 对象中)
lambda 可以为您做的其他事情是捕获范围、构建闭包。例如,如果您有这样的内容:
您拥有的函数像以前一样接受参数,但添加的金额取自变量的值。即使在定义 acc 的范围结束后,lambda 仍然可以存在。
您可以使用 lambda 构建非常简洁的东西,但您必须小心,因为有时您会因为这样的技巧而失去可读性。
Well, you can see a lambda as a quick way to write a method that you only want to use once. For instance, the following method
is equivalent to the lambda:
(n) => n + 5
. Except that you can call the method anywhere in your class, and the lambda lives only in the scope it is declared (You can also store lambdas in Action and Func objects)Other thing that lambdas can do for you is capturing scope, building a closure. For example, if you have something like this:
What you have there is a function that accepts an argument as before, but the amount added is taken from the value of the variable. The lambda can live even after the scope in which acc was defined is finished.
You can build very neat things with lambdas, but you have to be careful, because sometimes you lose readability with tricks like this.
正如其他人所说,lambda 表达式是函数的一种表示法。它将表达式右侧的自由变量绑定到左侧的参数。
创建一个函数,将表达式 (a + 1) 中的自由变量 a 绑定到函数的第一个参数并返回该函数。
Lambda 非常有用的一种情况是当您使用它们来处理列表结构时。 System.Linq.Enumerable 类提供了许多有用的函数,允许您使用 Lambda 表达式和实现 IEnumerable 的对象。例如,Enumerable.Where 可用于过滤列表:
输出将为“苹果、芒果、葡萄”。
尝试理解这里发生了什么:表达“fruit =>”水果长度< 6 创建一个函数,如果参数的 Length 属性小于 6,则返回 true。Enumerable.Where
循环遍历 List 并创建一个新 List,其中仅包含所提供的函数返回 true 的元素。这使您无需编写迭代列表、检查每个元素的谓词并执行某些操作的代码。
As others have said, a lambda expression is a notation for a function. It binds the free variables in the right-hand-side of the expression to the parameters on the left.
creates a function that binds the free variable a in the expression (a + 1) to the first parameter of a function and returns that function.
One case where Lambdas are extremely useful is when you use them to work with list structures. The System.Linq.Enumerable class provides a lot of useful functions that allow you to work with Lambda expressions and objects implementing IEnumerable. For example Enumerable.Where can be used to filter a list:
The output will be "apple, mango, grape".
Try to understand what's going on here: the expression fruit => fruit.Length < 6 creates a function which return true if the parameter's Length property is less than 6.
Enumerable.Where loops over the List and creates a new List which contains only those elements for which the supplied function returns true. This saves you to write code that iterates over the List, checks a predicate for each element and does something.
针对那些熟悉编码但不熟悉 lambda 的开发人员提供了一个很好的简单解释
TekPub 上的这个简单视频TekPub - 概念:#2 Lambdas
您显然在这里有很多反馈,但这是另一个很好的来源和一个简单的解释。
One good simple explanation aimed at developers who are firmiliar with coding but not with lambdas is this simple video on TekPub
TekPub - Concepts: #2 Lambdas
You obviously have lots of feedback here, but this is another good source and a simple explanation.
我知道这有点老了,但我来这里是为了理解所有这些 lambda 的东西。
当我完成所有答案和评论时,我对 lambda 有了更好的理解,并认为我应该添加这个简单的答案(从学习者的角度到学习者):
不要混淆
a =>; a + 1
意思是a加1并将结果返回给a。 (这很可能会让初学者感到困惑。相反,应该这样看:a 是函数(未命名函数)的输入参数,a + 1 是函数中的语句(“动态”构造的未命名函数)。
希望这有帮助:)
I know this is kinda old but i came here trying to make sense of all this lambda stuff.
By the time i finished pouring over all the answers and comments, i had a better understnading of lambda and thought i should just add this simple answer(from a learner's perspective to learners):
Dont confuse
a => a + 1
as meaning add 1 to a and return the result to a. (this is most likely a source of confusion for beginners.Instead see it like this: a is the input parameter into a function(unnamed function) and a + 1 is the statement(s) in the function(unnamed function constructed 'on the fly').
Hope this helps :)
Lambda 演算在许多编程语言中都很常见。在某些语言中它们也称为匿名函数。尽管不同的语言对 lambda 的语法不同,但原理是相同的,并且它们的各个部分通常是相同的。
也许最著名的就是 Javascript 的匿名函数。
有什么区别?好吧,有时您不想经历创建一个函数的麻烦,只是为了将它传递到某个地方一次,然后再也不会。
您可以查看维基百科文章以获取独立信息,或者您可以直接跳至编程中的 Lambda 在同一篇文章中。
Lambda calculus is common in many programming languages. They're also called anonymous functions in some languages. Though different languages have different syntax for lambda, the principle is the same, and their various parts are usually identical.
Perhaps the most famous one is Javascript's anonymous functions.
What's the difference? Well, sometimes you don't want to go through the trouble of creating a function just to pass it somewhere once and then never again.
You can see the wikipedia article for indept information or you can skip directly to Lambda in programming in the same article.
这只是 C# 写下函数值的表示法。它不需要为函数命名,因此该值有时称为匿名函数。其他语言有其他符号,但它们总是包含参数列表和主体。
最初的符号由 Alonzo Church 为其1930 年代的 Lambda 演算 在表达式
λx.t
中使用希腊字符 lambda 来表示函数,因此得名。This is just the notation of C# to write down a function value. It doesn't require giving the function a name, hence this value is sometimes called an anonymous function. Other languages have other notations, but they always contain a parameter list and a body.
The original notation invented by Alonzo Church for his Lambda calculus in the 1930ies used the greek character lambda in the expression
λx.t
to represent a function, hence the name.我理解 lambda 基础知识的技巧有两个。
首先我建议学习函数式编程。在这方面,Haskell 是一种很好的入门语言。我正在使用的书是 Programming in Haskell格雷厄姆·赫顿著。这为 Haskell 提供了良好的基础,并包括 lambda 的解释。
从那里我认为你应该查看 Erik Meijer 关于函数式编程的讲座,因为他们给出了很好的还介绍了函数式编程,同样使用 Haskell,并跨入 C#。
一旦您掌握了所有内容,您就应该能够很好地理解 lambda 了。
My tip for understanding the basics of lambdas is two fold.
Firstly I recommend learning about functional programming. Haskell is a good language to start off with in that respect. The book I am using, and getting a lot out of, is Programming in Haskell by Graham Hutton. This gives a good grounding in Haskell and includes explanations of lambdas.
From there I think you should view Erik Meijer's lectures on Functional Programming as they give a great intro to functional programming as well, also using Haskell, and crossing over into C#.
Once you've taken in all that you should be well on the way to understanding lambdas.
CodeProject 最近有一篇很好的介绍性文章: C# 委托、匿名方法和 Lambda 表达式 – O My!
CodeProject had a nice introductory article lately: C# Delegates, Anonymous Methods, and Lambda Expressions – O My!