我已经尝试了相当长的一段时间(阅读在线博客和文章),但到目前为止都没有成功弄清楚。
委托(delegates)是什么?Lambda表达式又是什么?它们各自的优缺点是什么?使用其中一个还是另一个的可能最佳实践是什么?
提前感谢您。
我已经尝试了相当长的一段时间(阅读在线博客和文章),但到目前为止都没有成功弄清楚。
委托(delegates)是什么?Lambda表达式又是什么?它们各自的优缺点是什么?使用其中一个还是另一个的可能最佳实践是什么?
提前感谢您。
delegate void OneArgumentDelegate(string argument);它本身什么也不做,就像接口一样。如果您在任何类中有一个具有这样一个参数的方法:
void SomeMethod(string someArgument) {}它与该委托的签名匹配,因此可以将其分配给其类型的变量:
OneArgumentDelegate ThisIsAVariable = new OneArgumentDelegate(SomeMethod); OneArgumentDelegate ThisIsAlsoAVariable = SomeMethod; // 简写也可以这些可以作为参数传递给方法并被调用,如下所示:
void Main() { DoStuff(PrintString); }这将输出
void PrintString(string text) { Console.WriteLine(text); }
void DoStuff(OneArgumentDelegate action) { action("Hello!"); }
Hello!
。DoStuff(PrintString)
的简写,因此您不必为要使用的每个委托变量创建一个方法。您'创建'一个传递给方法的临时方法。它的工作方式如下:
DoStuff(string text => Console.WriteLine(text)); // 单行 DoStuff(string text => // 多行 { Console.WriteLine(text); Console.WriteLine(text); });Lambda表达式只是一种简写,您也可以创建单独的方法并将其传递。希望您现在更好地理解它了;-)
DoStuff(PrintString)
的简写可能在选择示例时不太幸运。请考虑 DoStuff(text => Console.WriteLine(text));
只是 DoStuff(Console.WriteLine);
更冗长的写法,因为你的 lambda 与 Console.WriteLine
具有完全相同的签名:它们都是一个接受字符串并返回 void 的方法。 - David Hedlundstring
,正如@DavidHedlund的评论所述... - SlowLearner当您使用基于方法的语法调用Enumerable类中的Where方法时(如在LINQ to Objects和LINQ to XML中所做的那样),参数是委托类型System.Func。Lambda表达式是创建该委托的最方便的方法。当您在例如System.Linq.Queryable类中调用相同的方法(如在LINQ to SQL中所做的那样)时,参数类型是System.Linq.Expressions.Expression,其中Func是任何具有多达16个输入参数的Func委托。同样,Lambda表达式只是构造该表达式树的一种非常简洁的方式。虽然实际上从Lambda创建的对象类型不同,但这些lambda使得Where调用看起来相似。
没有人提到匿名委托。您可以在不声明委托的情况下即时创建委托:
public void Action(Func<int, int> func);
...
Action(delegate(int x) { return x*x; });
这只是lambda语法更加冗长的一种形式:
Action(x => x*x);
注意,lambda语法具有更激进的类型推断。另一个区别是,lambda符号可以用于声明表达式树:
public void Action(Expression<Func<int, int>>);
Action(x => x*x);
在使用lambda表达式和委托时,有一个重要的区别。
private delegate int emptymethoddel();
// Delegate for method with no params and returns int
相应的框架委托类型是:Func<int>
但是你无法从参数化方法创建新的委托实例/函数。
private int TwoArgMethod(int i, int j)
{
return i + j;
}
但是,使用 lambda
,您可以获得上述方法的委托。
Func<int> retmethod = () => TwoArgMethod(10, 20);
但是对于委托实例化,我们不能像下面这样做:
emptymethoddel retmethod4 = new emptymethoddel(TwoArgMethod(10,20));
// mismatch method signature
通过lambda,我们可以获得指向不匹配“Func”或任何其他变体的方法的指针。
委托就是函数指针。它就像一个“变量”,可以保存另一个将被调用的函数的地址。
public class test {
Action<int> CallUserCode;
public test(Action<int> proc){
CallUserCode = proc;
}
void foo(){
int someValue = 0;
//do some stuff that needs to call the user procedure
CallUserCode(someValue);
}
}
void bar(){
var t = new test(x => { /* do something with the value i get from foo */});
t.foo(); //here function foo gets called, which will call 'do something' AND call my lambda expression
}
正如其他人所说,lambda是一种用于内联和匿名创建委托的语法。使用lambda可以做到传统函数无法实现的闭包功能。这样,您就可以在运行时使用运行时信息创建函数:
string mystring = SomeObject.GetMyString();
AnotherObject.OnSomeEvent += (eventparams =>
{
string newstring = string.Format(eventparams.Message, mystring);
SomeService.PrintEvent(newstring);
}
这样,mystring 就被合并到委托中,可以作为一个变量使用。