参数类型’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("")
似乎很奇怪,以便让它工作。
有人可以解释一下我不理解的两件事吗?
- 为什么我不能像调用Do那样写第三行
- 为什么我必须写动作(“”)才能让它在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"));
- 期望一个
Action
(即不带参数且不返回任何值的方法)。 因此WriteToConsoleWithSomethingExtra
不是有效的拟合 – 需要一个字符串参数。 - 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 }