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);
}
}
此代码无法编译并导致以下错误消息:
方法的类型参数 'ThreadPoolTest.Sample.M(TParam1)'无法推断出来 用法。尝试指定类型参数 明确地
为什么在此示例中没有类型推断?
答案 0 :(得分:9)
类型推断只能将参数用于方法调用。就类型推断而言,将结果分配给double
这一事实完全无关紧要。换句话说,就编译器而言,它需要弄清楚这意味着什么:
Sample.M((int) 121)
没有任何更多信息。例如,你可以指Sample.M<int, int>
,Sample.M<double, int>
或Sample.M<string, int>
- 没有信息,所以说哪一个更匹配。
您没有在参数列表中提及T
,因此类型推断无济于事。
答案 1 :(得分:7)
Jon的回答当然是对的。它正在考虑为什么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);
好的,现在怎么样?如果关于“正在分配给什么”的类型信息必须在中将流向M上的类型推断,那么必须流入的类型信息是“它可以是int或double”。
但等等,这是对的吗?我们可以在这里做出更多关于可能的返回类型的逻辑推论。
如果它是int,那么我们有N(M<int, int>(123), 456)
并且N
因此它不能是int,对吗?它必须是double,因为那意味着调用是N(M<int, double>(123), 456)
,这明确地是第二次重载。
现在假设这样做是为了调用形式Q(R(S(N(M(......每个都有十几个重载,也许还有几个lambdas)。分析变得非常复杂;用户很难正确实现并且难以理解他们的程序是什么,为什么会产生错误以及如何修复它们。
简单地说表达式的类型分析必须根据其内容而不是其上下文来确定要容易得多。这就是我们的工作。您在编译器中抛出的重载解决问题必须是可解决的,而不必查看问题的上下文;我们只查看参数列表的内容来解决问题,并且参数列表中没有足够的信息。
现在,lambdas就是例外。 Lambda参数类型是从它们的上下文中推断出来的,因此,您可以轻松地强制编译器为深度嵌套的lambda尝试数万亿个可能的类型赋值,以解决重载解决问题。但我们不想将分析lambda的困难扩展到整个语言;我们希望将这些困难狭隘地局限于需要它们的特定语言特征。
答案 2 :(得分:0)
因为您没有指定返回类型。
这就是你想要的:
double d = Sample.M<double, int>((int)121);