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)'的类型参数.尝试显式指定类型参数
为什么在这个例子中没有类型推断?
类型推断只能使用方法调用的参数.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在参数列表中提及,因此类型推断无济于事.
乔恩的回答当然是正确的.它正在考虑为什么在做出推论时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的困难扩展到整个语言; 我们希望将这些困难狭隘地限制在需要它们的特定语言特征中.
| 归档时间: |
|
| 查看次数: |
308 次 |
| 最近记录: |