了解Lambda表达式和委托

use*_*521 14 c# lambda delegates .net-3.5

我一直试图解决这个问题很长一段时间(阅读在线博客和关键词),但到目前为止还没有成功.

代表们是什么?什么是Lambda表达式?两者的优点和缺点?何时使用其中一种可能的最佳做法?

提前致谢.

Jou*_*aas 28

委托是可以用作变量的方法,比如字符串等.例如,您可以使用一个参数声明委托方法:

delegate void OneArgumentDelegate(string argument);

它没有做任何事情,就像一个界面.如果你在任何类中有一个方法,有一个这样的参数:

void SomeMethod(string someArgument) {}

匹配委托的签名,因此可以分配给其类型的变量:

OneArgumentDelegate ThisIsAVariable = new OneArgumentDelegate(SomeMethod);
OneArgumentDelegate ThisIsAlsoAVariable = SomeMethod; // Shorthand works too

然后可以将这些作为参数传递给方法并调用,如下所示:

void Main()
{
  DoStuff(PrintString);
}

void PrintString(string text)
{
  Console.WriteLine(text);
}

void DoStuff(OneArgumentDelegate action) 
{
  action("Hello!");
}

这将输出Hello!.

Lambda表达式是一种简写,DoStuff(PrintString)因此您不必为要使用的每个委托变量创建一个方法.您'创建'传递给方法的临时方法.它的工作原理如下:

DoStuff(string text => Console.WriteLine(text)); // single line
DoStuff(string text => // multi line
{
  Console.WriteLine(text);
  Console.WriteLine(text);
});

Lambda表达式只是一种简写,你也可以创建一个单独的方法并传递它.我希望你现在能更好地理解它;-)

  • @Chris我想把它留下来,但为了清楚起见决定反对它.将它留在这里可能会让那些不熟悉语法的人感到困惑.在"真正的"代码中,我通常会将其排除在外,正如您所建议的那样. (3认同)

ULy*_*ses 6

Delegate是一个包含对函数的引用的对象.几个不同的代表可能指向相同的功能.甲代表的类型定义也可以指向一个函数的占地面积.

Lambda表达式是一个没有名称的函数.执行此函数的唯一方法是让一个委托指向该函数.Lambda表达式通常定义在需要委托给具有给定覆盖区的函数的位置.这有助于使代码更简洁,同时更具描述性和灵活性

我建议你使用一个命名函数和一个委托,只要你有一些代码将从不同的地方调用.一个常见示例是您要附加到多个事件生成器的事件侦听器.

考虑编写单独函数的另一点是代码的复杂性.如果你在lambda表达式中编写一个完整的程序,它对任何人都无济于事.

另一方面,您经常需要一些简单的处理,希望以回调的方式执行.这是你可能喜欢 lambda表达式的地方.

lambda表达式非常好,它们继承了它们定义的范围,因此您可以轻松地将变量放在lambda表达式中,从而传递大量信息.你应该小心,看到的备注部分 文章.

Labdas与LINQ合作非常出色.

最后,我必须引用另一个必读的msdn部分:

当您使用基于方法的语法来调用Enumerable类中的Where方法时(就像在LINQ to Objects和LINQ to XML中那样),参数是委托类型System.Func.lambda表达式是创建该委托的最便捷方式.当你在例如System.Linq.Queryable类中调用相同的方法时(就像你在LINQ to SQL中那样),那么参数类型是一个System.Linq.Expressions.Expression,其中Func是任何Func委托,最多16个输入参数.同样,lambda表达式只是构造表达式树的一种非常简洁的方式.lambda允许Where调用看起来类似,尽管实际上从lambda创建的对象类型是不同的.


Gab*_*art 5

没有人提到匿名代表。您可以即时创建委托,而无需声明它们:

public void Action(Func<int, int> func);
...
Action(delegate(int x) { return x*x; });
Run Code Online (Sandbox Code Playgroud)

这只是 lambda 语法的更详细版本:

Action(x => x*x);
Run Code Online (Sandbox Code Playgroud)

另请注意,lambda 语法具有更积极的类型推断。另一个区别是 lambda 表示法可用于声明表达式树:

public void Action(Expression<Func<int, int>>);
Action(x => x*x);
Run Code Online (Sandbox Code Playgroud)

在这种情况下,您得到的不是一个函数,而是一个可以在运行时检查的解析树。例如,这就是 linq 查询构建其 sql 的方式。

编辑

为了更直接地回答何时使用其中之一的问题:

您很少需要自己声明新的委托类型,尽管它有时会有所帮助。该框架提供了多种Func<>类型,以及Action<T>通常Predicate<T>您所需要的所有类型。

当“即时”创建函数时,使用匿名委托语法而不是 lambda 语法没有任何优势。由于 lambda 语法更加简洁并且可以进行类型推断,因此更喜欢它。