【问题标题】:Argument type 'void' is not assignable to parameter type 'System.Action'参数类型“void”不可分配给参数类型“System.Action”
【发布时间】:2010-08-02 12:36:22
【问题描述】:

这是我的测试代码:

class PassingInActionStatement
{
    static void Main(string[] args)
    {
        var dsufac = new DoSomethingUsefulForAChange();

        dsufac.Do(WriteToConsole);
        dsufac.Do2(s => WriteToConsoleWithSomethingExtra("Test"));
        dsufac.Do(WriteToConsoleWithSomethingExtra("Test")); // Does not compile
    }

    internal static void WriteToConsole()
    {
        Console.WriteLine("Done");
    }

    internal static void WriteToConsoleWithSomethingExtra(String input)
    {
        Console.WriteLine(input);
    }
}

internal class DoSomethingUsefulForAChange
{
    internal void Do(Action action)
    {
        action();
    }

    internal void Do2(Action<String> action)
    {
        action("");
    }
}

前两个电话有效,但我想知道为什么第三个电话无效。我不喜欢 Do2 中的代码,因为我在其中输入类型 action("") 以使其工作似乎很奇怪。

谁能解释一下我不明白的两件事?

  1. 为什么我不能像调用 Do 那样写第三行
  2. 为什么我必须编写 action("") 才能让它在 Do2 中工作

【问题讨论】:

  • 我总是标记对我有帮助的回复。如果没有提供有用的解决方案,我不会标记它,直到我得到对我有帮助的答案。

标签: c# c#-3.0


【解决方案1】:
dsufac.Do(WriteToConsoleWithSomethingExtra("Test"));

实际上是先调用函数(WriteToConsoleWithSomethingExtra("Test")),然后尝试将结果传递给Do。由于没有结果(void),所以不可能。

你真正想要的是这个:

dsufac.Do(() => WriteToConsoleWithSomethingExtra("Test"));

内部声明一个什么都不带的函数(() =&gt; 位),它在执行时调用WriteToConsoleWithSomethingExtra("Test")然后您的dsufac.Do 调用将收到一个操作,正如它所期望的那样。

至于Do2 - 您已将其声明为采用Action&lt;String&gt;,这意味着action 是一个采用一个参数 的函数。你必须给它一个字符串。该字符串可能是空的,就像在您的 action("") 示例中一样,或者它可能是从外部传入的,如下所示:

dsufac.Do3(WriteToConsole, "Test");

...

internal void Do3(Action<String> action, String str)
{
    action(str);
}

【讨论】:

  • 哇!这样可行。我仍然有很多关于 Action 和 Func 的问题。除了 MSDN 或您可以推荐的书籍之外,是否还有一些不错的教程?我会在允许的情况下标记您的答案(显然必须再等……分钟)。
【解决方案2】:

在您的代码中

dsufac.Do(WriteToConsoleWithSomethingExtra("Test"));

解释如下

var variable = WriteToConsoleWithSomethingExtra("Test");
dsufac.Do(variable);

由于 WriteToConsoleWithSomethingExtra("Test") 的返回类型为 void,因此您实际上不能将其传递给 dsufac.Do()。这就是为什么它没有被编译。但是对于第一个

dsufac.Do(WriteToConsole);

您没有调用该函数,而是将其作为方法组传递,稍后在 dsufac 对象的 Do() 方法中调用该方法组。但是如果你想把第 3 行写成第 1 行,你可以使用

dsufac.Do(() => WriteToConsoleWithSomethingExtra("Test"));

【讨论】:

    【解决方案3】:
    1. Do 期望 Action(即不带参数且不返回值的方法)。因此WriteToConsoleWithSomethingExtra 不是一个有效的拟合 - 接受一个字符串参数。
    2. Do2 接受Action&lt;T&gt;(即接受一个 T 参数但不返回值的方法)。因此,当您调用委托/操作时,您需要提供一个 T 类型的参数,这里是 String。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-08-27
      • 2021-08-24
      • 2021-08-05
      • 1970-01-01
      • 2023-04-05
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多