类型推断不起作用

Win*_*ter 3 c# type-inference

class Sample
{
    public static T M<T, TParam1>(TParam1 param1)
    {
        return default(T);
    }
}
class Program
{
    static void Main(string[] args)
    {

        double d = Sample.M((int)121);
    }
}
Run Code Online (Sandbox Code Playgroud)

此代码不编译并导致以下错误消息:

无法从用法推断出方法'ThreadPoolTest.Sample.M(TParam1)'的类型参数.尝试显式指定类型参数

为什么在这个例子中没有类型推断?

Jon*_*eet 9

类型推断只能使用方法调用的参数.double就类型推断而言,将结果分配给a的事实完全无关紧要.换句话说,就编译器而言,它需要弄清楚这意味着什么:

Sample.M((int) 121)
Run Code Online (Sandbox Code Playgroud)

没有更多信息.例如,你可能意味着Sample.M<int, int>,或者Sample.M<double, int>,或者Sample.M<string, int>- 没有信息,所以说哪一个是更好的匹配.

您没有T在参数列表中提及,因此类型推断无济于事.


Eri*_*ert 7

乔恩的回答当然是正确的.它正在考虑为什么在做出推论时C#不考虑"返回类型".这里的基本原则是类型信息在分析表达式时从流动,而不是从流动.

在你的特定情况下,很明显预期的返回类型是什么,因为你正在分配一些明确地加倍的东西.但是在很多情况下它并不明显:

static R M<A, R>(A a) { return default(R); }
static void N(int x, double y) {}
static void N(double x, int y) {}
...
N(M(123), 456);
Run Code Online (Sandbox Code Playgroud)

好的,现在怎么样?如果对"什么是被分配到"必须流类型的信息新的M类型推理则是在流动的类型信息是"它可能是int或double".

但等等,这是正确的吗?我们可以在这里做出更多关于可能的返回类型的逻辑推论.

如果它是int,那么我们有NN(M<int, int>(123), 456)N的重载解析将失败,因为该调用是不明确的; 它可能是N的版本!

因此它不能是int,对吗?它必须是double,因为那意味着调用N(M<int, double>(123), 456)明确地是第二次重载.

现在假设这样做是为了调用形式Q(R(S(N(M(......每个都有十几个重载,也许还有几个lambdas).分析变得非常复杂;它得到了很难正确和难以实现用户理解他们的程序做什么,为什么会产生错误,以及如何解决它们.

简单地说,表达式的类型分析必须根据其内容而不是其上下文来确定.这就是我们的工作.您在编译器中抛出的重载解决问题必须是可解决的,而不必查看问题的上下文; 我们只查看参数列表的内容来解决问题,并且参数列表中没有足够的信息.

现在,lambdas就是例外.Lambda参数类型从它们的上下文推断出来的,因此,您可以轻松地强制编译器为深度嵌套的lambda尝试数万亿个可能的类型赋值,以解决重载解决问题.但我们不想将分析lambda的困难扩展到整个语言; 我们希望将这些困难狭隘地限制在需要它们的特定语言特征中.