委托关键字与lambda表示法
一旦编译完成,是否有区别:
delegate { x = 0; }
和
() => { x = 0 }
?
简短的回答:不。
较长的答案,可能不相关:
- 如果将lambda分配给委托types(例如
Func
或Action
),则会得到一个匿名委托。 - 如果将lambda分配给Expressiontypes,则将获得expression式树而不是匿名委托。 然后可以将expression式树编译为匿名委托。
编辑:这里有一些expression式的链接。
- System.Linq.Expression.Expression(TDelegate) (从这里开始)。
- Linq在内存中与委托(如System.Func)使用System.Linq.Enumerable 。 Linq到SQL(以及其他)与expression式使用System.Linq.Queryable 。 检查这些方法的参数。
- ScottGu的一个解释 。 简而言之,Linq在内存中会产生一些匿名方法来解决你的查询。 Linq to SQL将生成表示查询的expression式树,然后将该树翻译成T-SQL。 Linq to Entities将生成一个表示查询的expression式树,然后将该树翻译成平台相应的SQL。
我喜欢大卫的回答,但我认为我会很迂腐。 这个问题说:“一旦编译完成” – 这表明这两个expression式都被编译了。 他们怎么能编译,但有一个被转换为一个委托,一个转换为expression式树? 这是一个棘手的 – 你必须使用匿名方法的另一个function; 唯一不被lambdaexpression式共享的。 如果指定一个匿名方法而不指定参数列表,则它与任何返回void的委托types兼容,且不带任何out
参数。 有了这些知识,我们应该能够构build两个超载,使expression式完全无歧义,但是却有很大的不同。
但灾难来袭! 至less在C#3.0中,您不能将带有块体的lambdaexpression式转换为expression式,也不能将lambdaexpression式转换为正文中的赋值(即使它用作返回值)。 这可能会改变C#4.0和.NET 4.0,它允许更多的expression式在expression式树中。 换句话说,就像MojoFilter恰好给出的例子,两者几乎总是会被转换成相同的东西。 (更多细节在一分钟内。)
如果我们稍微改变一下主体,我们可以使用委托参数技巧:
using System; using System.Linq.Expressions; public class Test { static void Main() { int x = 0; Foo( () => x ); Foo( delegate { return x; } ); } static void Foo(Func<int, int> action) { Console.WriteLine("I suspect the anonymous method..."); } static void Foo(Expression<Func<int>> func) { Console.WriteLine("I suspect the lambda expression..."); } }
可是等等! 如果我们足够狡猾,即使不使用expression树,我们也可以区分两者。 下面的例子使用重载parsing规则(和匿名委托匹配技巧)…
using System; using System.Linq.Expressions; public class Base { public void Foo(Action action) { Console.WriteLine("I suspect the lambda expression..."); } } public class Derived : Base { public void Foo(Action<int> action) { Console.WriteLine("I suspect the anonymous method..."); } } class Test { static void Main() { Derived d = new Derived(); int x = 0; d.Foo( () => { x = 0; } ); d.Foo( delegate { x = 0; } ); } }
哎哟。 记住孩子,每当你重载一个从基类inheritance的方法,一只小猫开始哭泣。
大卫B是正确的。 请注意,使用expression式树可能会有好处。 LINQ to SQL将检查expression式树并将其转换为SQL。
您也可以使用lamdas和expression式树来玩技巧,以重构安全的方式将类成员的名称有效地传递给框架。 Moq就是一个例子。
在上面的两个例子中,没有区别,零。
expression方式:
() => { x = 0 }
是一个带有声明主体的Lambdaexpression式,所以它不能被编译为expression式树。 事实上,它甚至不编译,因为它需要在0之后的分号:
() => { x = 0; } // Lambda statement body () => x = 0 // Lambda expression body, could be an expression tree.
有一个区别
例:
var mytask = Task.Factory.StartNew(() => { Thread.Sleep(5000); return 2712; }); mytask.ContinueWith(delegate { _backgroundTask.ContinueTask(() =>lblPercent.Content = mytask.Result.ToString(CultureInfo.InvariantCulture)); });
我用lambdareplace:(错误)
var mytask = Task.Factory.StartNew(() => { Thread.Sleep(5000); return 2712; }); mytask.ContinueWith(()=> { _backgroundTask.ContinueTask(() =>lblPercent.Content = mytask.Result.ToString(CultureInfo.InvariantCulture)); });