C#编译器是否无法按预期的返回类型推断方法类型参数?

时间:2011-01-12 02:52:35

标签: c# type-inference

这对我来说似乎很奇怪,但我记得Eric Lippert评论过C#的基于返回类型的重载方法无法(通过设计,或者至少是惯例,我认为)的一个线程,所以也许它是以某种令人费解的方式与此有关。

有什么理由不起作用:

public static T Test<T>() where T : new()
{
    return new T();
}

// Elsewhere
SomeObject myObj = Test();

但这样做:

 var myObj = Test<SomeObject>();

从某个角度看,它们都很好,因为你不是在重复自己(以非常小的方式),但这只是编译器的不同传递吗?

5 个答案:

答案 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)

如果您想要一个为什么的示例,表达式的类型需要能够由表达式本身确定,请考虑以下两种情况:

  1. 我们根本不使用返回值 - 我们只是调用方法来产生副作用。
  2. 我们将返回值直接传递给重载方法
  3. 当涉及到泛型类型解析时,使用返回值的“期望类型”会在编译器中引入额外复杂性,并且您获得的所有内容是有时您需要明确指定类型,有时候你没有,你是否需要根据代码中其他地方的无关更改进行更改。