为什么C#编译器不能从函数签名推断泛型类委托?

McG*_*gle 7 c# generics functional-programming type-inference currying

我正在使用一个函数,它接受两个函数作为参数,并返回一个新的组合函数:

public static Action<T> Compose<T>(Action<T> first, Action second)
{
    return new Action<T>(arg =>
    {
        first(arg);
        second();
    });
}
Run Code Online (Sandbox Code Playgroud)

我注意到编译器抱怨如果我没有指定T,当发送静态或成员函数(而不是实际Action<T>对象)时:

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);
}
Run Code Online (Sandbox Code Playgroud)

错误消息:

无法从用法中推断出方法'ConsoleTest.Program.Compose(System.Action,System.Action)'的参数.尝试显式指定类型参数.

我的问题:为什么不能在这里推断出类型论证?签名Test是在编译时知道的,不是吗?是否真的有一些功能可以代替Test,这会导致它的签名含糊不清?

附注:我知道我可以简单地发送new Action<string>(Test),而不是TestCompose(在注意这个问题) -我的问题是"为什么",而不是"我怎样才能做到这一点."

p.s*_*w.g 6

我想它可能与以下事实有关:至少从编译器的角度来看,Test实际上是一个'方法组',直到编译器确定它将具有哪些类型的参数.即使组中只有一个Test方法(当前范围中只有一个方法),也是如此.

注意:

var composed = Compose<object>(Test, () => Console.WriteLine(" world"));
Run Code Online (Sandbox Code Playgroud)

产生错误:

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

参数1:无法从'方法组'转换为' System.Action<object>'

但这很好:

var composed = Compose<string>(Test, () => Console.WriteLine(" world"));
Run Code Online (Sandbox Code Playgroud)

我的猜测是编译器在某种意义上将两个方法组表达式(Test)和隐式键入的泛型方法调用(Compose)视为"未绑定".它无法完全确定从参数类型的"未绑定"签名中选择方法组中的哪个方法Compose,并且无法Compose从签名中确定哪个类型类型参数.它需要一个或另一个'绑定'才能编译整个语句.

  • 看起来你走在正确的轨道上......这里有更多的讨论,在这里:http://stackoverflow.com/a/6231921/1001985 (2认同)