【问题标题】:What is the difference between new Action() and a lambda?new Action() 和 lambda 有什么区别?
【发布时间】:2010-10-20 10:33:54
【问题描述】:

所以当我写这样的东西时

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

重构专业版!将其突出显示为冗余委托创建,并允许我将其缩短为

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

这通常效果很好。 通常,但并非总是如此。例如,Rhino Mocks 有一个名为 Do 的扩展方法:

IMethodOptions<T> Do(Delegate action);

在这里,传递第一个版本有效,但第二个无效。这里到底发生了什么?

【问题讨论】:

  • 您的第二个代码块无法编译。我收到此消息“无法将 lambda 表达式分配给隐式类型的局部变量”。但是,如果我将“var”替换为“Action”就可以了。
  • 是的,你是对的,它不能分配给隐式类型的变量,我会编辑它。

标签: c# .net-3.5 delegates lambda


【解决方案1】:

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

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

IMethodOptions<T> Do(Action action);

这样你就可以同时使用这两个语句并且不会有任何不同:

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

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

请阅读以下链接以获取有关 Action 和 Delegate 的更多信息:https://docs.microsoft.com/en-gb/dotnet/api/system.action?view=netframework-4.7.1#definition

【讨论】:

    【解决方案2】:

    第一个版本正在有效地做:

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

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

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

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

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

    如果 action 是用 var 声明的,C# 编译器如何计算出它应该是什么类型?

    在调用方法时解决这个问题的最简单方法(对于您的 Rhino Mocks 示例)是强制转换:

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

    【讨论】:

    • VB.Net 能够通过根据使用情况动态生成委托类型来解决这个问题。因为 VB 已经区分了 void 和非 void 返回函数(子和函数),所以区分更容易
    • “如果 C# 编译器使用 var 声明,它如何计算出动作的类型?”简单:函数类型应该是一流的结构类型,而不是这个命名的委托东西。并且引用的代码应该这样注明。但我想现在这不会改变:)。
    • 我认为你需要在 lambda 周围加上一对圆括号来进行这样的转换。
    • @H.B.完成 - 我总是对在转换 lambda 时需要多少个括号感到惊讶:)
    • @JonSkeet:这就是我在这些情况下使用new Action(() =&gt; ...) 的原因。
    【解决方案3】:

    您是否验证了第二行实际编译?它不应该编译,因为 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

    【讨论】:

      猜你喜欢
      • 2018-08-02
      • 2011-11-22
      • 1970-01-01
      • 1970-01-01
      • 2017-10-31
      • 2018-06-04
      • 2012-12-29
      • 1970-01-01
      • 2015-08-24
      相关资源
      最近更新 更多