new Action()和lambda有什么区别?

时间:2009-04-19 19:53:26

标签: c# .net-3.5 delegates lambda

所以当我写这样的东西时

Action action = new Action(()=>_myMessage = "hello");

Refactor Pro!突出显示这是一个冗余的委托创建,并允许我将其缩短为

Action action = () => _myMessage="hello";

这通常很有效。 通常,但并非总是如此。例如,Rhino Mocks有一个名为Do:

的扩展方法
IMethodOptions<T> Do(Delegate action);

这里,传递第一个版本有效,但第二个版本没有。究竟是什么在这里?

3 个答案:

答案 0 :(得分:58)

第一个版本实际上是这样做的:

Action tmp = () => _myMessage = "hello";
var action = new Action(tmp);

您遇到的问题是编译器必须知道lambda表达式应该转换为什么类型的委托(或表达式树)。这就是为什么:

var action = () => _myMessage="hello";

实际上没有编译 - 它可能是任何委托类型,没有参数,也没有返回值或与_myMessage相同的返回类型(可能是string )。例如,所有这些都是有效的:

Action action = () => _myMessage="hello";
Func<string> action = () => _myMessage="hello";
MethodInvoker action = () => _myMessage="hello";
Expression<Action> = () => _myMessage="hello";
// etc

如果用action声明它,那么C#编译器如何计算var的类型?

调用方法(对于你的Rhino Mocks示例)时最简单的方法是转换:

methodOptions.Do((Action) (() => _myMessage = "hello"));

答案 1 :(得分:9)

您确认第二行实际编译了吗?它不应该编译,因为C#不支持将lambda表达式赋值给隐式类型变量(CS0815)。这行可以在VB.Net中使用,因为它支持匿名委托创建(从VB 9.0开始)。

Rhino Mocks版本的编译原因与第二行不应编译的原因相同。 C#不会自动推断lambda表达式的类型。 Lambda表达式必须在可以确定它们要实现的委托类型的上下文中使用。第一行很有用,因为预期的类型很明确:Action。 Rhino Mocks版本不起作用,因为Delegate更类似于抽象委托类型。它必须是具体的委托类型,例如Action或Func。

有关此主题的详细讨论,您应该阅读Eric Lippert关于此主题的博客条目:http://blogs.msdn.com/ericlippert/archive/2007/01/11/lambda-expressions-vs-anonymous-methods-part-two.aspx

答案 2 :(得分:1)

Action是一种特殊类型的委托。因此,如果你使用lambda将无法理解你想要使用哪种类型,因为有许多(Action,Func,...)

要克服对(在大多数情况下速度很慢)的需求,您可以将基本函数的参数从Delegate更改为Action:

IMethodOptions<T> Do(Action action);

这样你就可以使用这两种语句而不会有任何不同:

Action action = new Action(()=>_myMessage = "hello"); 
Action action = () => _myMessage="hello";

如果这不可行,那么我建议使用 new Action(()=&gt; {})而不是强制转换,它会更快。

请阅读以下链接,了解有关操作和代表的更多信息:https://docs.microsoft.com/en-gb/dotnet/api/system.action?view=netframework-4.7.1#definition