.NET Framework中lambda和委托有什么区别?

Sco*_*oon 76 .net c# lambda

我被问到这个问题很多,我想我会就如何最好地描述差异征求一些意见.

Chr*_*man 88

它们实际上是两个非常不同的东西."Delegate"实际上是包含对方法或lambda的引用的变量的名称,而lambda是没有永久名称的方法.

除了一些微妙的差异外,Lambdas与其他方法非常相似.

  1. 普通方法在"语句"中定义并绑定到永久名称,而lambda在"表达式"中 "在运行中"定义,并且没有永久名称.
  2. 一些lambdas可以与.NET表达式树一起使用,而方法则不能.

委托定义如下:

delegate Int32 BinaryIntOp(Int32 x, Int32 y);
Run Code Online (Sandbox Code Playgroud)

只要签名相同,BinaryIntOp类型的变量可以为其分配方法或labmda:两个Int32参数和一个Int32返回.

lambda可能定义如下:

BinaryIntOp sumOfSquares = (a, b) => a*a + b*b;
Run Code Online (Sandbox Code Playgroud)

另外需要注意的是,虽然通用的Func和Action类型通常被认为是"lambda类型",但它们就像任何其他委托一样.关于它们的好处是它们实际上为您可能需要的任何类型的委托定义了一个名称(最多4个参数,但您当然可以添加更多自己的参数).因此,如果您使用各种各样的委托类型,但只能使用一次,则可以使用Func和Action避免使用委托声明来混淆代码.

以下是Func和Action如何"不只是为了lambdas"的例证:

Int32 DiffOfSquares(Int32 x, Int32 y)
{
  return x*x - y*y;
}

Func<Int32, Int32, Int32> funcPtr = DiffOfSquares;
Run Code Online (Sandbox Code Playgroud)

另一个有用的事情是,具有相同签名但名称不同的委托类型(不是方法本身)不会隐式地相互转换.这包括Func和Action代理.但是,如果签名相同,则可以在它们之间显式转换.

更加努力......在C#中,函数是灵活的,使用lambdas和delegates.但是C#没有"一流的功能".您可以使用分配给委托变量的函数名称来创建表示该函数的对象.但它确实是一个编译技巧.如果您通过编写函数名称后跟一个点来启动语句(即尝试对函数本身进行成员访问),您会发现没有成员可以参考.甚至不是来自Object的那些.这可以防止程序员做一些有用的(当然也可能是危险的)诸如添加可以在任何函数上调用的扩展方法.你可以做的最好的是扩展Delegate类本身,这肯定也很有用,但不是那么多.

更新:另请参阅Karg的答案,说明匿名委托与方法和lambda之间的区别.

更新2:詹姆斯·哈特提出了一个重要但非常技术性的说明,即lambdas和委托不是.NET实体(即CLR没有委托或lambda的概念),而是它们是框架和语言结构.


Jam*_*art 29

问题有点含糊不清,这解释了你得到的答案的广泛差异.

你实际上问过.NET框架中lambda和委托之间的区别; 这可能是众多事情之一.你问:

  • lambda表达式和C#(或VB.NET)语言中的匿名委托有什么区别?

  • System 3.5中的System.Linq.Expressions.LambdaExpression对象和System.Delegate对象有什么区别?

  • 或者在这些极端之间或周围的某个地方?

有些人似乎试图给你答案"C#Lambda表达式与.NET System.Delegate之间的区别是什么?"这个问题并没有多大意义.

.NET框架本身并不理解匿名委托,lambda表达式或闭包的概念 - 这些都是由语言规范定义的.想想C#编译器如何将匿名方法的定义转换为生成的类上的方法,并使用成员变量来保持闭包状态; 到.NET,没有关于委托的匿名; 对于编写它的C#程序员来说,它只是匿名的.对于分配给委托类型的lambda表达式同样如此.

什么.NET DOES理解为代表的想法-它描述的方法签名类型,它们的实例代表或者绑定调用特定对象上,或者绑定调用特定方法,以特定的方法对特定类型,可以对被调用任何该类型的对象,其中所述方法遵守所述签名.这些类型都继承自System.Delegate.

.NET 3.5还引入了System.Linq.Expressions命名空间,该命名空间包含用于描述代码表达式的类 - 因此也可以表示对特定类型或对象上的方法的绑定或未绑定调用.然后可以将LambdaExpression实例编译为实际的委托(从而基于表达式结构的动态方法是代码生成的,并返回指向它的委托指针).

在C#中,您可以通过将lambda表达式赋值给所述类型的变量来生成System.Expressions.Expression类型的实例,这将生成在运行时构造表达式的相应代码.

当然,如果你询问lambda表达式和C#中的匿名方法之间什么区别,那么所有这些都是非常相关的,在这种情况下,主要的不同之处在于简洁,当你不这样做时,它会向匿名代表倾斜.关心参数并且不打算返回值,并且当你想要类型推断参数和返回类型时,朝向lambdas.

lambda表达式支持表达式生成.

  • 好消息!你激励我启动反射器,看看IL.我不知道lambdas导致了生成的类,但是现在我想起来它是完全合理的. (3认同)

Kar*_*arg 19

一个区别是匿名委托可以省略参数,而lambda必须匹配确切的签名.鉴于:

public delegate string TestDelegate(int i);

public void Test(TestDelegate d)
{}
Run Code Online (Sandbox Code Playgroud)

你可以用以下四种方式调用它(注意第二行有一个没有任何参数的匿名委托):

Test(delegate(int i) { return String.Empty; });
Test(delegate { return String.Empty; });
Test(i => String.Empty);
Test(D);

private string D(int i)
{
    return String.Empty;
}
Run Code Online (Sandbox Code Playgroud)

您不能传入没有参数的lambda表达式或没有参数的方法.这些是不允许的:

Test(() => String.Empty); //Not allowed, lambda must match signature
Test(D2); //Not allowed, method must match signature

private string D2()
{
    return String.Empty;
}
Run Code Online (Sandbox Code Playgroud)


Dan*_*eld 13

委托等同于函数指针/方法指针/回调(接受你的选择),lambdas是非常简化的匿名函数.至少那是我告诉别人的.