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(); }
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.
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.
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 :)
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.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 :)
CodeProject had a nice introductory article lately: C# Delegates, Anonymous Methods, and Lambda Expressions – O My!