.NET:静态方法的推断泛型类型

Che*_*eso 15 .net c# generics type-inference c#-3.0

假设我有

public static List<T2> Map<T,T2>(List<T> inputs, Func<T, T2> f)
{
    return inputs.ConvertAll((x) => f(x));
}

private int Square(int x) { return x*x; }

public void Run()
{
    var inputs = new List<Int32>(new int[]{2,4,8,16,32,64,128,256,512,1024,2048});

    // this does not compile
    var outputs = Map(inputs, Square); 

    // this is fine
    var outputs2 = Map<Int32,Int32>(inputs, Square);

    // this is also fine (thanks, Jason)
    var outputs2 = Map<Int32,Int32>(inputs, (x)=>x*x);

    // also fine
    var outputs2 = Map(inputs, (x)=>x*x);
}
Run Code Online (Sandbox Code Playgroud)

为什么不编译?

编辑:错误是:

错误CS0411:无法从用法推断出方法'Namespace.Map <T,T2>(System.Collections.Generic.List <T>,System.Func <T,T2>)'的类型参数.尝试显式指定类型参数.

为什么我必须指定Map()函数的类型?它能否从传递中推断出来Func<T>?(就我而言,Square)


答案是否与
C#3.0泛型类型推断相同 - 将委托作为函数参数传递

jas*_*son 10

从您的错误消息:

方法' [...].Map<T,T2>(System.Collections.Generic.List<T>, System.Func<T,T2>)' 的类型参数不能从用法中推断出来.尝试显式指定类型参数.

请注意,错误消息表明它无法找出类型参数.也就是说,它无法解析其中一个类型参数TT2.这是因为规范的§25.6.4(类型参数的推断).这是规范中涉及推断泛型类型参数的部分.

如果满足以下任何条件,则从参数中推断出任何内容(但类型推断成功):

[...]

参数是方法组.

因此,编译器无法使用委托类型Square来推断其类型T2.请注意,如果您将声明更改为

public static List<T> Map<T>(List<T> inputs, Func<T, T> f) {
        return inputs.ConvertAll((x) => f(x));
}
Run Code Online (Sandbox Code Playgroud)

然后

var outputs = Map(inputs, Square);
Run Code Online (Sandbox Code Playgroud)

是合法的.在这种情况下,它已经解决了Tint一个事实,即inputsList<int>.

现在,更深层次的问题是为何上述规范?也就是说,为什么方法组不能在类型参数解析中发挥作用?我认为这是因为这样的情况:

class Program {
    public static T M<T>(Func<T, T> f) {
        return default(T);
    }

    public static int F(int i) {
        return i;
    }

    public static float F(float f) {
        return f;
    }

    static void Main(string[] args) {
        M(F); // which F am I?
    }
}
Run Code Online (Sandbox Code Playgroud)