参数类型“void”无法赋值给参数类型“System.Action”。

20

这是我的测试代码:

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. 为什么我必须在Do2中写入action("")才能使它正常工作。

我总是标记帮助过我的答复。如果没有提供有用信息的解决方案,我不会标记它,直到我得到真正帮助我的答案。 - Nyla Pareska
3个回答

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

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

你真正想要的是这个:

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

内部部分声明了一个不带参数的函数(() =>),当执行时调用WriteToConsoleWithSomethingExtra("Test")然后,您的dsufac.Do调用将接收到一个动作,就像它期望的那样。

至于Do2 - 您已将其声明为Action<String>,这意味着action是一个带有一个参数的函数。您必须向其传递一个字符串。该字符串可能为空,就像您的action("")示例中一样,或者可能由外部传入,例如以下内容:

dsufac.Do3(WriteToConsole, "Test");

...

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

哇!这个方法可行。我仍然遇到了很多与 Action 和 Func 相关的问题。除了 MSDN 或书籍,您能建议一些不错的教程吗?当它允许我标记您的答案时,我会这样做(显然需要等待另外...分钟)。 - Nyla Pareska

3

在你的代码中

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

被解释为以下内容:

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

由于WriteToConsoleWithSomethingExtra("Test")的返回类型为void,因此您实际上无法将其传递给dsufac.Do()。这就是为什么它不能被编译。但对于第一个问题,您可以使用以下代码:
dsufac.Do(WriteToConsole);

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

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

1
  1. Do 需要一个 Action(即不带参数且不返回值的方法)。因此,WriteToConsoleWithSomethingExtra 不是一个有效的选择 - 它需要一个字符串参数。
  2. Do2 接受一个 Action<T>(即接受一个 T 类型参数且不返回值的方法)。因此,当你调用委托/操作时,你需要提供一个类型为 T 的参数,这里是字符串。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接