为什么C#编译器不能从函数签名推断generics类委托?
我正在使用一个函数,它将两个函数作为参数,并返回一个新的组合函数:
public static Action Compose(Action first, Action second) { return new Action(arg => { first(arg); second(); }); }
我注意到编译器抱怨如果我没有指定T
,当发送静态或成员函数时(而不是实际的Action
对象):
static void Main(string[] args) { // compiler error here var composed = Compose(Test, () => Console.WriteLine(" world")); composed("hello"); Console.ReadLine(); } public static void Test(string arg) { Console.Write(arg); }
错误消息:
无法从用法中推断出方法’ConsoleTest.Program.Compose(System.Action,System.Action)’的参数。 尝试显式指定类型参数。
我的问题 :为什么不能在这里推断出类型论证? Test
的签名在编译时是已知的,不是吗? 是否真的有一些function可以代替Test
,这会导致它的签名不明确?
脚注:我知道我可以简单地发送new Action(Test)
而不是Test
to Compose
(如本问题中所述 ) – 我的问题是“为什么”,而不是“我怎么能这样做”。
我想它可能与以下事实有关:至少从编译器的角度来看, Test
实际上是一个’方法组’,直到编译器确定它将具有哪些类型的参数。 即使组中只有一个方法(当前范围中只有一个Test
方法),也是如此。
注意:
var composed = Compose
产生错误:
‘
Compose
‘的最佳重载方法匹配有一些无效的参数参数1:无法从’方法组’转换为’
System.Action
‘
但这很好:
var composed = Compose(Test, () => Console.WriteLine(" world"));
我的猜测是编译器在某种意义上将两个方法组表达式( Test
)和隐式类型的generics方法调用( Compose
)视为“未绑定”。 它无法完全确定从方法组中选择哪种方法从参数类型’未绑定’签名到Compose
,并且无法从签名中确定Compose
的类型类型参数。 它需要一个或另一个’绑定’才能编译整个语句。
这可能与协方差有关。 尽管已知Test
的参数类型,但您可能希望创建更具体类型的委托。
public class BaseClass { } public class DerivedClass : BaseClass { } static class Program { static void Main(string[] args) { var composed = Compose(Test, () => Console.WriteLine(" world")); composed(new DerivedClass()); Console.ReadLine(); } public static void Test(BaseClass arg) { Console.Write(arg); } }