关键字与 lambda 表示法

一旦编译完成,下列两者之间是否有区别:

delegate { x = 0; }

还有

() => { x = 0 }

73690 次浏览

简短的回答: 不。

更长的答案可能与本文无关:

  • 如果您将 lambda 分配给一个委托类型(如 FuncAction) ,您将获得一个匿名委托。
  • 如果将 lambda 分配给 Expression 类型,则会得到一个表达式树,而不是匿名委托。然后可以将表达式树编译为匿名委托。

编辑: 这里有一些表达式的链接。

在上面的两个例子中没有区别,零。

这句话的意思是:

() => { x = 0 }

是一个带有语句体的 Lambda 表达式,因此不能将其编译为表达式树。事实上,它甚至不能编译,因为它需要在0后面加一个分号:

() => { x = 0; } // Lambda statement body
() => x = 0      // Lambda expression body, could be an expression tree.

艾米 · B 说得对。注意,使用表达式树有很多优点。LINQtoSQL 将检查表达式树并将其转换为 SQL。

您还可以使用 lamdas 和表达式树来以重构安全的方式有效地将类成员的名称传递给框架。莫克就是一个例子。

我喜欢艾米的回答,但我觉得我太迂腐了。问题是,“一旦它被编译”——这表明两个表达式 都被编译了。它们如何同时编译,但是一个被转换为委托,一个被转换为表达式树?这是一个棘手的问题-您必须使用匿名方法的另一个特性; 这是唯一一个不被 lambda 表达式共享的特性。如果指定匿名方法而没有指定参数列表 完全没有,则它与返回 void 的任何委托类型兼容,并且没有任何 out参数。有了这些知识,我们应该能够构造两个重载,使表达式完全明确,但非常不同。

但是灾难降临了!至少在 C # 3.0中,不能将带块主体的 lambda 表达式转换为表达式,也不能将带赋值的 lambda 表达式转换为主体中的表达式(即使它被用作返回值)。这可能会随着 C # 4.0和。NET 4.0,它允许在表达式树中表达更多内容。换句话说,在 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...");
}
}

等等!如果我们足够狡猾的话,即使不使用表达式树,我们也可以区分这两者。下面的示例使用重载解析规则(以及匿名委托匹配技巧) ..。

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

哎哟,孩子们,记住,每次你重载从基类继承的方法时,一只小猫就开始哭了。

这是有区别的

例如:

var mytask = Task.Factory.StartNew(() =>
{
Thread.Sleep(5000);
return 2712;
});
mytask.ContinueWith(delegate
{
_backgroundTask.ContinueTask(() =>lblPercent.Content = mytask.Result.ToString(CultureInfo.InvariantCulture));
});

我用 lambda 替换: (错误)

var mytask = Task.Factory.StartNew(() =>
{
Thread.Sleep(5000);
return 2712;
});
mytask.ContinueWith(()=>
{
_backgroundTask.ContinueTask(() =>lblPercent.Content = mytask.Result.ToString(CultureInfo.InvariantCulture));
});

这里有一些基本知识。

这是一个匿名方法

(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);