为什么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(Test, () => Console.WriteLine(" world")); 

产生错误:

Compose(System.Action, System.Action) ‘的最佳重载方法匹配有一些无效的参数

参数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); } }