参数类型’System.Action’不能赋予参数类型’void’

这是我的测试代码:

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 action) { action(""); } } 

前2个电话有效,但我想知道为什么第3个电话没有。 我不喜欢Do2中的代码,因为我在那里有类型类型action("")似乎很奇怪,以便让它工作。

有人可以解释一下我不理解的两件事吗?

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

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

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

你真正想要的是这个:

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

内部部分声明一个不带任何内容的函数( () => )位),它在执行时调用WriteToConsoleWithSomethingExtra("Test")然后你的dsufac.Do调用将收到一个动作,就像它期望的那样。

对于Do2 – 您已将其声明为采用Action ,这意味着action是一个接受一个参数的函数 。 你必须传递一个字符串。 该字符串可能为空,例如在您的action("")示例中,或者它可能在外部传递,如下所示:

 dsufac.Do3(WriteToConsole, "Test"); ... internal void Do3(Action action, String str) { action(str); } 

在你的代码中

 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")); 
  1. 期望一个Action (即不带参数且不返回任何值的方法)。 因此WriteToConsoleWithSomethingExtra不是有效的拟合 – 需要一个字符串参数。
  2. Do2接受Action (即接收一个T参数并且不返回值的方法)。 因此,当您调用委托/操作时,您需要提供一个类型为T的参数,此处为String。

我在Silverlight应用程序中做了一段时间这样的事情。 现在,当它运行时,其中一部分会中断。
这发生在Silverlight子窗口中:

 (my object context).SaveChanges(() => ChangesSaved()); private void ChagngesSaved() { DialogResult = true: // is supposed to close the child window. line gets hit, does not close }