Lambda for Dummies…anyone, anyone? I think not

2020-05-11 10:47发布

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(); }

标签: c#-3.0 lambda
10条回答
走好不送
2楼-- · 2020-05-11 11:29

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

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

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:

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

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.

查看更多
爱情/是我丢掉的垃圾
3楼-- · 2020-05-11 11:36

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.

查看更多
狗以群分
4楼-- · 2020-05-11 11:37

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:

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

If you were to use this method normally on say a List and select each element twice (that is concatenated to itself):

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

...

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

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:

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

Or, with explicit parameters stated

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

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.

查看更多
我命由我不由天
5楼-- · 2020-05-11 11:37

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.

a => a + 1

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:

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);
}

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.

查看更多
登录 后发表回答