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

Mar*_*ger 6 c# type-inference

这对我来说似乎很奇怪,但我记得一个帖子,Eric Lippert评论了基于返回类型的C#重载方法无法(通过设计,或者至少是惯例,我认为),所以也许它有一些与之相关的复杂方式.

有什么理由不起作用:

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

// Elsewhere
SomeObject myObj = Test();
Run Code Online (Sandbox Code Playgroud)

但这样做:

 var myObj = Test<SomeObject>();
Run Code Online (Sandbox Code Playgroud)

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

Eri*_*ert 5

首先,这是"基于返回类型的重载":

void M(int x){...}
int M(int x){...}
string M(int x){...}
Run Code Online (Sandbox Code Playgroud)

声明是不合法的; 您不能基于返回类型重载方法,因为返回类型不是签名的一部分,并且签名必须是唯一的.

你在谈论的是基于方法的返回类型的方法类型推断.我们也不支持.

原因是因为返回类型可能是您想要弄清楚的.

M(Test());
Run Code Online (Sandbox Code Playgroud)

什么是测试的返回类型?这取决于我们选择的M超载.我们选择M的超载量是多少?这取决于Test的返回类型.

通常,C#的设计使得每个子表达式都有一个类型,并且类型从"内部"向"外部"而不是从外部到内部进行计算.

值得注意的例外是匿名函数,方法组和null:

M(x=>x+1)
Run Code Online (Sandbox Code Playgroud)

什么是x => x + 1的类型?这取决于M的哪个过载被称为.

M(N); // N is a method group
Run Code Online (Sandbox Code Playgroud)

N的类型是什么?同样,它取决于调用M的哪个过载.

等等.在这些情况下,我们从"外部"到"内部"进行推理.

涉及lambda的类型推断非常复杂并且难以实现.我们不希望在整个编译器中遇到同样的复杂性和困难.


Che*_*hen 3

检查C#语言规范\xc2\xa77.5.2,变量的声明类型不是类型推断的证明,显然也不应该是。考虑以下代码:

\n\n
Base b = Test<Derived>();\nDerived d = Test<Derived>();\n
Run Code Online (Sandbox Code Playgroud)\n\n

该方法的返回类型可能与变量的声明类型不同,因为我们在 C# 中具有隐式转换。

\n