这对我来说似乎很奇怪,但我记得Eric Lippert评论过C#的基于返回类型的重载方法无法(通过设计,或者至少是惯例,我认为)的一个线程,所以也许它是以某种令人费解的方式与此有关。
有什么理由不起作用:
public static T Test<T>() where T : new()
{
return new T();
}
// Elsewhere
SomeObject myObj = Test();
但这样做:
var myObj = Test<SomeObject>();
从某个角度看,它们都很好,因为你不是在重复自己(以非常小的方式),但这只是编译器的不同传递吗?
答案 0 :(得分:5)
首先,这是“基于返回类型的重载”:
void M(int x){...}
int M(int x){...}
string M(int x){...}
声明不合法;您不能基于返回类型重载方法,因为返回类型不是签名的一部分,并且签名必须是唯一的。
您所谈论的是基于方法的返回类型的方法类型推断。我们也不支持。
原因是因为返回类型可能是您想要弄清楚的。
M(Test());
什么是测试的返回类型?这取决于我们选择的M超载。我们选择M的超载量是多少?这取决于测试的返回类型。
一般来说,C#的设计是为了使每个子表达都有一个类型,并且类型从“内部”向“外部”计算,而不是从外部到内部。
值得注意的例外是匿名函数,方法组和null:
M(x=>x+1)
x =&gt; x + 1的类型是什么?这取决于M的哪个超载被调用。
M(N); // N is a method group
N的类型是什么?同样,它取决于M的哪个过载被调用。
等等。在这些情况下,我们从“外部”到“内部”进行推理。
涉及lambda的类型推断非常复杂,难以实现。我们不希望整个编译器都有同样的复杂性和困难。
答案 1 :(得分:4)
除了无类型表达式(null
,方法组和lambda表达式)之外,表达式的类型必须由表达式本身静态地确定,而不管上下文如何。
换句话说,表达式Test()
的类型不能取决于您为其分配的内容。
答案 2 :(得分:3)
检查C#语言规范§7.5.2,变量的声明类型不是类型推断的证明,显然它不应该是。请考虑以下代码:
Base b = Test<Derived>();
Derived d = Test<Derived>();
该方法的返回类型可能与变量的声明类型不同,因为我们在C#中进行了隐式转换。
答案 3 :(得分:1)
编译器的类型推断不会将赋值的“期望类型”用作逻辑的一部分。
因此,类型推断的“考虑范围”不是这样的:
SomeObject myObj = Test();
但是这个:
Test();
而且,这里没有关于预期类型的线索。
答案 4 :(得分:1)
如果您想要一个为什么的示例,表达式的类型需要能够由表达式本身确定,请考虑以下两种情况:
当涉及到泛型类型解析时,使用返回值的“期望类型”会在编译器中引入额外复杂性,并且您获得的所有内容是有时您需要明确指定类型,有时候你没有,你是否需要根据代码中其他地方的无关更改进行更改。