我一直试图解决这个问题很长一段时间(阅读在线博客和关键词),但到目前为止还没有成功。
什么是代表?什么是Lambda表达式?两者的优点和缺点?何时使用其中一种可能的最佳做法?
提前致谢。
答案 0 :(得分: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表达式只是一种简写,你也可以创建一个单独的方法并传递它。我希望你现在能更好地理解它; - )
答案 1 :(得分:6)
委托是一个包含对函数的引用的对象。几个不同的代表可能指向相同的功能。 委托的类型定义了它可能指向的函数的足迹。
Lambda表达式是一个没有名称的函数。执行此功能的唯一方法是让委托指向该功能。 Lambda表达式通常定义在需要委托给具有给定足迹的函数的位置。这对于使代码更简洁,同时更具描述性和灵活性非常有用
我建议你使用一个命名函数和一个委托,只要你有一些代码将从不同的地方调用。一个常见示例是您要附加到多个事件生成器的事件侦听器。
考虑编写单独函数的另一点是代码的复杂性。如果你在lambda表达式中编写一个完整的程序,那对任何人都无济于事。
另一方面,您经常需要一些想要以回调方式执行的简单处理。这就是你可能喜欢 lambda表达式的地方。
lambda表达式非常好,它们继承了它们定义的范围,因此您可以轻松地将您的变量放在lambda表达式中,从而传递大量信息。你应该小心,请参阅备注部分 this文章。
Labdas与LINQ合作非常出色。
总而言之,我必须引用yet another必读的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表达式只是构造表达式树的一种非常简洁的方式。 lambdas允许Where调用看起来类似,尽管实际上从lambda创建的对象类型是不同的。
答案 2 :(得分:3)
没有人提到过匿名代表。您可以动态创建委托,而无需声明它们:
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);
在这种情况下,您获得的不是函数,而是可以在运行时检查的解析树。例如,这就是linq查询构建sql的方式。
修改强>
更直接地回答何时使用其中一个的问题:
您很少需要自己声明新的委托类型,尽管偶尔会有所帮助。该框架提供了多种Func<>
类型,以及Action<T>
和Predicate<T>
,这些通常都是您需要的。
在“动态”创建函数时,使用匿名委托语法而不是lambda语法没有任何好处。由于lambda语法更简洁且类型推断,所以更喜欢它。
答案 3 :(得分:2)
Delegate只是指向函数的指针。它就像一个“变量”,你可以将地址保存到另一个名为
的函数中 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);
}
}
Lambda表达式也是一个委托,它具有简化的语法,可以“创建”“内联”函数。 因此,前面的示例将使用lambda以下列方式调用。
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
}
答案 4 :(得分:2)
有一个重要的区别是我们可以使用lamda而不是委托。
private delegate int emptymethoddel();
// Delegate for method with no params and returns int
等效的框架委托类型是:Func<int>
但是你不能从参数化方法创建新的委托实例/ func。
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”或任何其他变体不匹配的方法的指针。
答案 5 :(得分:1)
正如其他人所说,lambdas是一种内联和匿名创建委托的语法。使用传统功能无法实现的lambda可以做的一件事就是闭包。这样,您就可以在运行时使用运行时信息创建函数:
string mystring = SomeObject.GetMyString();
AnotherObject.OnSomeEvent += (eventparams =>
{
string newstring = string.Format(eventparams.Message, mystring);
SomeService.PrintEvent(newstring);
}
这样,mystring被合并到委托中,可以用作变量。