所以当我写这样的东西时
Action action = new Action(()=>_myMessage = "hello");
Refactor Pro!突出显示这是一个冗余的委托创建,并允许我将其缩短为
Action action = () => _myMessage="hello";
这通常很有效。 通常,但并非总是如此。例如,Rhino Mocks有一个名为Do:
的扩展方法IMethodOptions<T> Do(Delegate action);
这里,传递第一个版本有效,但第二个版本没有。究竟是什么在这里?
答案 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