我经常被问到这个问题,我想就如何最好地描述两者之间的差异征求一些意见。
我经常被问到这个问题,我想就如何最好地描述两者之间的差异征求一些意见。
Answers:
它们实际上是两件事。“ Delegate”实际上是持有对方法或lambda的引用的变量的名称,而lambda是没有永久名称的方法。
Lambda与其他方法非常相似,只是有一些细微的差异。
委托的定义如下:
delegate Int32 BinaryIntOp(Int32 x, Int32 y);
只要签名是相同的,则BinaryIntOp类型的变量可以分配一个方法或labmda:两个Int32参数和一个Int32返回。
Lambda可以这样定义:
BinaryIntOp sumOfSquares = (a, b) => a*a + b*b;
要注意的另一件事是,尽管通常将Func和Action类型定义为“ lambda类型”,但它们与其他任何委托一样。关于它们的好处是,它们实际上为您可能需要的任何类型的委托定义了一个名称(最多4个参数,尽管您当然可以添加更多自己的委托)。因此,如果您使用各种各样的委托类型,但不止一次,则可以通过使用Func和Action避免使用委托声明使代码混乱。
这是Func和Action如何“不仅仅用于lambda”的说明:
Int32 DiffOfSquares(Int32 x, Int32 y)
{
return x*x - y*y;
}
Func<Int32, Int32, Int32> funcPtr = DiffOfSquares;
要知道的另一件事是,具有相同签名但名称不同的委托类型(而不是方法本身)不会被隐式地强制转换为彼此。这包括Func和Action委托。但是,如果签名相同,则可以在它们之间显式转换。
更加努力。...在C#中,函数很灵活,可以使用lambda和委托。但是C#没有“一流的功能”。您可以使用分配给委托变量的函数名称来实质上创建表示该函数的对象。但这实际上是一个编译器技巧。如果通过在函数名称后加上点(例如尝试对函数本身进行成员访问)来编写语句,则会发现那里没有要引用的成员。甚至没有来自对象的。这样可以防止程序员做有用的(当然是潜在的危险)事情,例如添加可以在任何函数上调用的扩展方法。您可以做的最好的事情就是扩展Delegate类本身,这当然也很有用,但还不多。
更新:另请参阅Karg的答案,该答案说明了匿名委托与方法和lambda之间的区别。
更新2:James Hart提出了一个重要的建议,尽管非常技术性,但它指出lambda和委托不是.NET实体(即CLR没有委托或lambda的概念),而是它们是框架和语言构造。
这个问题有点模棱两可,这解释了您得到的答案之间的巨大差异。
您实际上问过.NET框架中的lambda和委托之间有什么区别;那可能是许多事情之一。您在问:
Lambda表达式和C#(或VB.NET)语言中的匿名委托之间有什么区别?
.NET 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#匿名方法之间,毕竟,那么这一切是非常irelevant,在这种情况下,主要的区别是简洁,当你穿上这对匿名委托斜靠”不必在意参数,也不要计划返回值,当您要输入推断的参数和返回类型时,请不要使用lambda。
lambda表达式支持表达式生成。
一个区别是,匿名委托可以省略参数,而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;
}
您不能传入不带参数的lambda表达式或不带参数的方法。这些是不允许的:
Test(() => String.Empty); //Not allowed, lambda must match signature
Test(D2); //Not allowed, method must match signature
private string D2()
{
return String.Empty;
}
委托基本上基本上只是一个函数指针。Lambda可以变成委托,但也可以变成LINQ表达式树。例如,
Func<int, int> f = x => x + 1;
Expression<Func<int, int>> exprTree = x => x + 1;
第一行产生一个委托,而第二行产生一个表达式树。
委托是函数签名;就像是
delegate string MyDelegate(int param1);
委托没有实现主体。
lambda是与委托签名匹配的函数调用。对于上述代表,您可以使用以下任何一种:
(int i) => i.ToString();
(int i) => "ignored i";
(int i) => "Step " + i.ToString() + " of 10";
但是,该Delegate
类型的名称很错误;创建类型的对象Delegate
实际上会创建一个可以容纳函数的变量-它们可以是lambda,静态方法或类方法。
很明显,这个问题的意思是“ lambda和匿名委托之间有什么区别?” 在所有答案中,只有一个人做对了-主要区别在于lambda可以用于创建表达式树和委托。
您可以在MSDN上阅读更多信息:http : //msdn.microsoft.com/zh-cn/library/bb397687.aspx
一些基本的。“委托”实际上是持有对方法或lambda的引用的变量的名称
这是一个匿名方法-
(string testString) => { Console.WriteLine(testString); };
由于匿名方法没有任何名称,因此我们需要一个可以在其中分配这两种方法或表达式的委托。对于前
delegate void PrintTestString(string testString); // declare a delegate
PrintTestString print = (string testString) => { Console.WriteLine(testString); };
print();
与lambda表达式相同。通常我们需要委托才能使用它们
s => s.Age > someValue && s.Age < someValue // will return true/false
我们可以使用func委托来使用此表达式。
Func< Student,bool> checkStudentAge = s => s.Age > someValue && s.Age < someValue ;
bool result = checkStudentAge ( Student Object);
这是我在la脚的博客上发表过的例子。假设您要通过工作线程更新标签。我有4个示例,说明如何使用委托,匿名委托和2种类型的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#-理解委托和lambda表达式。
一个(正常的,与所谓的泛型委托相反,后来称为cf)委托应该被视为一种typedef
函数指针类型的c ++,例如在c ++中:
R (*thefunctionpointer) ( T ) ;
typedef的类型thefunctionpointer
是指向函数的指针的类型,该函数采用typeT
的对象并返回type的对象R
。您可以这样使用它:
thefunctionpointer = &thefunction ;
R r = (*thefunctionpointer) ( t ) ; // where t is of type T
thefunction
一个将aT
并返回a的函数在哪里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
thefunction
一个将aT
并返回a的函数在哪里R
?这是给代表的,即所谓的普通代表。
现在,您在c#中还具有泛型委托,这些泛型委托是泛型的委托,即可以说是“模板化”的委托,因此使用c ++表达式。它们的定义如下:
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);
thefunction2
函数以哪里为参数并返回double
。
现在,想象一下,不是thefunction2
我想使用一个现在尚未在声明中定义的“函数”,而是以后将不再使用。然后,c#允许我们使用此函数的表达式。通过表达我的意思了“数学”(或功能性,坚持程序)它的表达,例如:到double x
我会相关联的double
x*x
。在数学中,您可以使用“ \ mapsto”乳胶符号编写此代码。在c#中借用了功能符号:=>
。例如 :
Func<double, double> thefunctor = ( (double x) => x * x ); // outer brackets are not
// mandatory
(double x) => x * x
是表达。它不是类型,而代理(泛型或非泛型)则是。
道德?最后,如果不是函数指针类型(resp.wrapped + smart + generic函数指针类型),那么委托是什么(分别是通用委托),是吗?还有别的!看到这个和那个。