在.NET Framework中,lambdas和委托有什么区别?

我被问了很多这个问题,我想我会征求一些关于如何最好地描述差异的意见。

他们实际上是两个完全不同的东西。 “委托”实际上是一个variables的名称,它包含对方法或lambda的引用,而lambda是没有永久名称的方法。

兰姆达斯非常像其他方法,除了一些细微的差异。

  1. 一个普通的方法被定义在一个“声明”中,并与一个永久名称绑定,而一个lambda被定义为“在expression式中”并且没有永久的名字。
  2. 有些lambda可以用于.NETexpression式树,而方法不能。

代表是这样定义的:

delegate Int32 BinaryIntOp(Int32 x, Int32 y); 

BinaryIntOptypes的variables可以有一个方法或labmda分配给它,只要签名是相同的:两个Int32参数和一个Int32返回。

lambda可以像这样定义:

 BinaryIntOp sumOfSquares = (a, b) => a*a + b*b; 

另外要注意的是,虽然通用的Func和Actiontypes通常被认为是“lambdatypes”,但它们就像任何其他代表一样。 关于他们的好处是,他们基本上为您可能需要的任何types的委托(最多4个参数,尽pipe您可以添加更多自己的参数)定义一个名称。 因此,如果您使用的委托types种类繁多,但只能使用一次,则可以通过使用Func和Action避免使用委托声明混淆代码。

下面是Func和Action如何“不仅仅是lambdas”的说明:

 Int32 DiffOfSquares(Int32 x, Int32 y) { return x*x - y*y; } Func<Int32, Int32, Int32> funcPtr = DiffOfSquares; 

另一个有用的知识是,具有相同签名但名称不同的委托types(不是方法本身)不会隐式地相互转换。 这包括Func和Action代表。 但是,如果签名是相同的,则可以明确地在它们之间进行投射。

加倍努力….在C#中,函数是灵活的,使用lambdas和委托。 但是C#没有“一stream的function”。 您可以使用分配给委托variables的函数名称来创build表示该函数的对象。 但它确实是一个编译器技巧。 如果你通过写一个点后面的函数名来启动一个语句(例如,尝试对函数本身进行成员访问),你会发现没有成员可以参考。 连Object都没有。 这可以防止程序员做一些有用的事情(当然也有潜在的危险),例如添加可以在任何函数上调用的扩展方法。 你可以做的最好的是扩展委托类本身,这当然也是有用的,但不是那么多。

更新:另请参阅Karg的答案,说明匿名代理与方法&lambdaexpression式之间的区别。

更新2: 詹姆斯·哈特(James Hart)提出了一个非常重要的技术问题,即lambdaexpression式和代表不是.NET实体(即CLR没有委托或lambda的概念),而是框架和语言结构。

这个问题有点模棱两可,这就解释了你所得到的答案的巨大差异。

你实际上问了.NET框架中lambdas和委托的区别是什么? 这可能是许多事情之一。 你问:

  • 在C#(或VB.NET)语言中,lambdaexpression式和匿名委托有什么区别?

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

  • 或者在这两个极端之间或之间的某个地方?

有些人似乎试图给出“C#Lambdaexpression式和.NET System.Delegate之间有什么区别”这个问题的答案,这个问题并没有太大的意义。

.NET框架本身并不了解匿名代理,lambdaexpression式或闭包的概念 – 这些都是由语言规范定义的东西。 考虑一下C#编译器如何将匿名方法的定义转换为生成类中的方法,其中成员variables保持闭包状态; 到.NET,没有什么匿名的委托, 它只是写给它的C#程序员的匿名。 这同样适用于分配给委托types的lambdaexpression式。

.NET能够理解的是代理的概念 – 一种描述方法签名的types,其实例表示对特定对象上的特定方法的绑定调用,或对可以调用的特定types的特定方法的未绑定调用该types的任何对象,其中所述方法遵守所述签名。 这些types都从System.Delegateinheritance。

.NET 3.5还引入了System.Linq.Expressions命名空间,它包含用于描述代码expression式的类,并且也可以表示对特定types或对象的方法的绑定或非绑定调用。 然后可以将LambdaExpression实例编译成实际的委托(由此基于expression式的结构的dynamic方法被编码,并且返回一个委托指针)。

在C#中,可以通过将一个lambdaexpression式分配给所述types的variables来生成System.Expressions.Expressiontypes的实例,这将生成适当的代码以在运行时构造expression式。

当然,如果你问C#中的lambdaexpression式和匿名方法之间的区别是什么,那么所有这些都是非常相关的,在这种情况下,主要的区别是简洁,当你不使用匿名方法时,不关心参数,不要计划返回一个值,当你想要input推断参数和返回types的时候,不要打算inputlambdas。

而lambdaexpression式支持expression式生成。

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

 public delegate string TestDelegate(int i); public void Test(TestDelegate d) {} 

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

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

你不能传入一个没有参数的lambdaexpression式或一个没有参数的方法。 这些是不允许的:

 Test(() => String.Empty); //Not allowed, lambda must match signature Test(D2); //Not allowed, method must match signature private string D2() { return String.Empty; } 

代表相当于函数指针/方法指针/callback(随便你select),lambdas是非常简化的匿名函数。 至less这就是我告诉人们的。

我对此没有太多的经验,但是我要描述的方式是委托是任何函数的包装器,而lambdaexpression式本身就是一个匿名函数。

委托总是基本上是一个函数指针。 一个lambda可以变成一个委托,但它也可以变成一个LINQexpression式树。 例如,

 Func<int, int> f = x => x + 1; Expression<Func<int, int>> exprTree = x => x + 1; 

第一行产生一个委托,而第二行产生一个expression式树。

lambdas只是一个委托语法糖。 编译器最终将lambda转换为委托。

我相信这些是一样的:

 Delegate delegate = x => "hi!"; Delegate delegate = delegate(object x) { return "hi";}; 

委托是函数签名; 就像是

 delegate string MyDelegate(int param1); 

代表没有实施一个机构。

lambda是一个匹配委托签名的函数调用。 对于上面的代表,你可以使用任何的;

 (int i) => i.ToString(); (int i) => "ignored i"; (int i) => "Step " + i.ToString() + " of 10"; 

尽pipe如此, Delegatetypes的命名Delegate糟糕。 创build一个Delegatetypes的对象实际上创build了一个可以容纳函数的variables – 无论是lambdaexpression式,静态方法还是类方法。

委托是对具有特定参数列表和返回types的方法的引用。 它可能包含也可能不包含对象。

lambdaexpression式是匿名函数的一种forms。

这个问题很明显就是“lambda和匿名代表之间有什么区别? 在这里所有的答案中,只有一个人得到了正确的答案 – 主要区别在于lambda可以用来创buildexpression树和代表。

你可以阅读更多关于MSDN: http : //msdn.microsoft.com/en-us/library/bb397687.aspx

代表实际上只是函数的结构types。 你可以用名义input和实现一个实现一个接口或抽象类的匿名类来做同样的事情,但是当只需要一个函数的时候,结果是代码很多。

Lambda来自20世纪30年代Alonzo教会的lambda演算的想法。 这是创build函数的匿名方式。 它们对组成函数特别有用

所以,虽然有人可能会说lambda是代表的语法糖,我会说代表是一个桥梁,以缓解人们在C#中的lambdas。

委托是一个函数指针的队列,调用一个委托可能会调用多个方法。 lambda本质上是一个匿名方法声明,它可以被编译器以不同的方式解释,这取决于它被用作什么上下文。

您可以通过将其转换为委托来获取指向lambdaexpression式的委托,或者将它作为parameter passing给需要特定委托types的方法,编译器会将其转换为您。 在LINQ语句中使用它,lambda将被编译器转换为expression式树而不是简单的委托。

不同之处在于,lambda是在另一个expression式中定义一个方法的简洁方法,而委托是一个实际的对象types。

Lambdas是代表的简化版本。 它们具有一些像匿名代理这样的闭包的属性,但也允许你使用隐含的键入。 像这样的lambda:

 something.Sort((x, y) => return x.CompareTo(y)); 

比使用委托可以做得更简洁:

 something.Sort(sortMethod); ... private int sortMethod(SomeType one, SomeType two) { one.CompareTo(two) } 

下面我举了一个例子,在我的跛脚博客上。 假设你想从工作者线程更新标签。 我有4个如何使用委托,匿名委托和2种types的lambda来更新1到50的标签的例子。

  private void button2_Click(object sender, EventArgs e) { BackgroundWorker worker = new BackgroundWorker(); worker.DoWork += new DoWorkEventHandler(worker_DoWork); worker.RunWorkerAsync(); } private delegate void UpdateProgDelegate(int count); private void UpdateText(int count) { if (this.lblTest.InvokeRequired) { UpdateProgDelegate updateCallBack = new UpdateProgDelegate(UpdateText); this.Invoke(updateCallBack, new object[] { count }); } else { lblTest.Text = count.ToString(); } } void worker_DoWork(object sender, DoWorkEventArgs e) { /* Old Skool delegate usage. See above for delegate and method definitions */ for (int i = 0; i < 50; i++) { UpdateText(i); Thread.Sleep(50); } // Anonymous Method for (int i = 0; i < 50; i++) { lblTest.Invoke((MethodInvoker)(delegate() { lblTest.Text = i.ToString(); })); Thread.Sleep(50); } /* Lambda using the new Func delegate. This lets us take in an int and * return a string. The last parameter is the return type. so * So Func<int, string, double> would take in an int and a string * and return a double. count is our int parameter.*/ Func<int, string> UpdateProgress = (count) => lblTest.Text = count.ToString(); for (int i = 0; i < 50; i++) { lblTest.Invoke(UpdateProgress, i); Thread.Sleep(50); } /* Finally we have a totally inline Lambda using the Action delegate * Action is more or less the same as Func but it returns void. We could * use it with parameters if we wanted to like this: * Action<string> UpdateProgress = (count) => lblT…*/ for (int i = 0; i < 50; i++) { lblTest.Invoke((Action)(() => lblTest.Text = i.ToString())); Thread.Sleep(50); } } 

我认为你的问题涉及的是c#而不是.NET,因为你的问题不明确,因为.NET并不是独自一人 – 也就是说,没有c# – 对委托和lambdaexpression式的理解。

A( 正常情况下 ,与所谓的generics委托相反, cf后面)委托应该被看作是一种函数指针types的c ++ typedef ,例如在c ++中:

 R (*thefunctionpointer) ( T ) ; 

typedef的types是函数指针,它是指向一个函数的指针types,它带有一个types为T的对象并返回一个types为R的对象。 你会这样使用它:

 thefunctionpointer = &thefunction ; R r = (*thefunctionpointer) ( t ) ; // where t is of type T 

函数将是一个函数,并返回一个R

在C#中,你会去的

 delegate R thedelegate( T t ) ; // and yes, here the identifier t is needed 

你可以像这样使用它:

 thedelegate thedel = thefunction ; R r = thedel ( t ) ; // where t is of type T 

函数将是一个函数,并返回一个R 这是代表,所谓的正常代表。

现在,你也可以在C#中使用generics委托,它们是通用的委托, 也就是说 ,可以这么说,使用c ++expression式。 他们是这样定义的:

 public delegate TResult Func<in T, out TResult>(T arg); 

你可以像这样使用它们:

 Func<double, double> thefunctor = thefunction2; // call it a functor because it is // really as a functor that you should // "see" it double y = thefunctor(2.0); 

函数2是一个函数作为参数并返回一个double

现在想象一下,我不想使用function2,而是使用一个现在没有定义的“function”,通过一个语句,而且我以后再也不会使用了。 然后c#允许我们使用这个函数的expression式 。 通过expression式我的意思是“math”(或function,坚持程序)的expression,例如:到一个double x我将关联 double x*x 。 在math中,你使用“\ mapsto”乳胶符号来写这个。 在c#中,函数表示法已经被借用: => 。 例如 :

 Func<double, double> thefunctor = ( (double x) => x * x ); // outer brackets are not // mandatory 

(double x) => x * x是一个expression式 。 这不是一种types,而代表(通用或不是)。

道德? 最后,什么是委托(resp。generic delegate),如果不是函数指针types(resp。wrapped + smart +generics函数指针types),呵呵? 别的东西! 看到这个和那个 。

那么,真正过于简单的版本是,lambda只是一个匿名函数的简写。 委托可以做的不仅仅是匿名函数:事件,asynchronous调用和多个方法链。