C# new Action()和lambda之间有什么区别?

C# new Action()和lambda之间有什么区别?,c#,.net-3.5,delegates,lambda,C#,.net 3.5,Delegates,Lambda,所以当我写这样的东西时 Action action = new Action(()=>_myMessage = "hello"); 重构专业!将其突出显示为冗余代理创建,并允许我将其缩短为 Action action = () => _myMessage="hello"; 这通常效果很好通常,但并不总是。例如,Rhino Mocks有一个名为Do: IMethodOptions<T> Do(Delegate action); i方法Do(委托操作); 在这里,传递

所以当我写这样的东西时

Action action = new Action(()=>_myMessage = "hello");
重构专业!将其突出显示为冗余代理创建,并允许我将其缩短为

Action action = () => _myMessage="hello";
这通常效果很好通常,但并不总是。例如,Rhino Mocks有一个名为Do:

IMethodOptions<T> Do(Delegate action);
i方法Do(委托操作);

在这里,传递第一个版本是可行的,但是第二个版本不行。封面下到底发生了什么事?

您是否验证了第二行的编译过程?它不应该编译,因为C#不支持将lambda表达式赋给隐式类型变量(CS0815)。但是,这一行在VB.Net中可以工作,因为它支持匿名委托创建(从VB9.0开始)

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


有关此主题的详细讨论,您应该阅读Eric Lippert关于此主题的博客文章:

第一个版本实际上在做:

Action tmp = () => _myMessage = "hello";
var action = new Action(tmp);
您遇到的问题是,编译器必须知道lambda表达式应转换为哪种类型的委托(或表达式树)。这就是为什么:

var action = () => _myMessage="hello";
实际上没有编译-它可以是没有参数、没有返回值或与
\u myMessage
相同的返回类型的任何委托类型(可能是
字符串
)。例如,所有这些都是有效的:

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

动作是一种特殊类型的委托。因此,如果您使用lambda,将无法理解您要使用的类型,因为有很多类型(Action、Func等)

为了克服这种强制转换的需要(在大多数情况下,这种转换很慢),您可以将基本函数的参数从委托更改为操作:

IMethodOptions<T> Do(Action action);
如果这不可能,那么我建议使用新操作(()=>{})而不是强制转换,这样会更快


有关操作和委托的更多信息,请阅读以下链接:

您的第二个代码块未编译。我收到这样一条消息“无法将lambda表达式分配给隐式类型的局部变量”。但是,如果我将“var”替换为“Action”,它确实可以。是的,你是对的,它不能被分配给隐式类型的变量,我将对其进行编辑。VB.Net可以通过根据使用情况动态生成委托类型来解决这一问题。因为VB已经区分了void和non-void返回函数(sub和function),这使得区分更容易“如果使用var声明,C#编译器如何计算出类型操作的含义?”很简单:函数类型应该是第一类结构类型,而不是这个命名的委托类型。引用的代码也应如此注明。但我想现在不会改变:)。我想你需要在lambda周围多加一对括号来进行这样的转换。@H.B.完成-我总是惊讶于你在转换lambda时需要多少括号:)@JonSkeet:这就是为什么我在这些情况下使用
新操作(()=>…)
IMethodOptions<T> Do(Action action);
Action action = new Action(()=>_myMessage = "hello"); 
Action action = () => _myMessage="hello";