【问题标题】:Action same as Func<TResult>?动作与 Func<TResult> 相同吗?
【发布时间】:2023-03-10 09:30:01
【问题描述】:

我遇到了需要一些知识的情况。

下面是代码:

// A function to match the delegate
public static int DoSomething()
{
   Console.WriteLine("i am called");
   return 1;
}

// Usage
Action action = () => DoSomething();
Func<int> func = () => DoSomething();
action();
func();

我以前对Action的理解是应该匹配一个不接受参数也不返回任何内容的委托。

对于Func&lt;int&gt;,它应该匹配一个不接受参数并返回int的委托。

DoSomething 方法返回一个整数,因此我的问题是:() =&gt; DoSomething() 是一个返回 int 的委托。 Func 按预期工作,但 Action 没有。为什么?我在这里有什么不明白的地方?

代码编译运行正常,均输出i am called。我想知道的是为什么Action action = () =&gt; DoSomething();不是编译时错误?

【问题讨论】:

  • >> 但 Action 没有 — 它究竟是如何失败的?
  • 代码行Action&lt;object&gt; action = (x) =&gt; DoSomething(x);,不应该是编译时错误,因为Action&lt;object&gt; 需要匹配不返回值的委托吗?
  • @singsuyash C# 编译器足够聪明,可以根据上下文确定(x) =&gt; DoSomething(x) 的含义不同。当您使用它来分配Action 变量时,它会生成Action,而不是Func,并忽略DoSomething(x) 的返回结果。
  • 您可以调用DoSomething 方法并“忽略”返回值(例如DoSomething(x)),您可以使用返回值(例如var retVal = DoSomething(x))- 两者都可以工作和编译。
  • 您的问题是什么?您的代码非常好,可以编译并运行

标签: c# .net lambda delegates


【解决方案1】:

我想知道为什么Action action = () =&gt; DoSomething(); 不是编译时错误?

它编译是因为你有一个调用方法但忽略结果的 lambda 表达式。您不能使用方法组转换,例如

// Compile-time failure
// error CS0407: 'int Test.DoSomething()' has the wrong return type
Action action = DoSomething; 

Func&lt;Action, int&gt;同样的方法组转换就可以了。)

但是,您正在做的事情更像这样:

Action action = DoSomethingAndIgnoreResult;
...
private static void DoSomethingAndIgnoreResult()
{
    DoSomething(); // Hey, I'm ignoring the result. That's fine...
}

【讨论】:

  • 值得注意的是,方法组转换的错误类似于Expected a method with 'void DoSomething(object)' signature
  • @DaveZych:完成,我收到了实际的错误消息。
  • 感谢@JonSkeet 提供更新的答案:) 是的,以后要小心不要像这样更改它。
【解决方案2】:

Action action = () =&gt; DoSomething(); 等价于
Action action = () =&gt; { DoSomething(); };

Func&lt;int&gt; func = () =&gt; DoSomething(); 等价于
Func&lt;int&gt; func = () =&gt; { return DoSomething(); };

【讨论】:

    【解决方案3】:

    C# 编译器足够聪明,可以根据上下文确定() =&gt; DoSomething() 的含义不同。当您使用它来分配Action 变量时,它会生成忽略DoSomething() 的返回结果的Action(而不是Func&lt;int&gt;)。

    【讨论】:

      【解决方案4】:

      DoSomething 方法返回一个整数,因此我的问题是:(x) =&gt; DoSomething(x) 是一个接受 object 并返回 int 的委托。 Func 按预期工作,但 Action 没有。为什么?我在这里有什么不明白的地方?

      你理解的缺陷就在这里:(x) =&gt; DoSomething(x) 没有类型。这不是什么。编译器需要上下文来确定这是什么类型。 lambda 本身并不是什么特别的东西,这就是为什么你不能将var 与 lambda 表达式一起使用:编译器不知道 lambda 应该是什么类型,所以它不能推断出类型。

      例如,(x) =&gt; DoSomething(x) 也可以是表达式树:

      Expression<Func<object, int>> e = (x) => DoSomething(x)
      

      所以你告诉编译器如何根据你分配给它的类型来解释一个 lambda。

      【讨论】:

        【解决方案5】:

        你所有的理解都是正确的。您的具体用法可能会引起混淆。 Func 和 Action 都很好。两个电话都很好。我认为可能阐明您的问题的案例是:

        var x = action(5); // NOT ok var y = func(5); // ok

        您的示例代码只是忽略了返回值,这就是为什么它们看起来是一样的。没有什么不同

        void Foo1(int x) { return; } void Foo2(int x) { return 1; } Foo1(5); Foo2(5);

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-07-18
          • 2013-11-15
          • 1970-01-01
          相关资源
          最近更新 更多