鉴于:
static TDest Gimme<TSource,TDest>(TSource source) { return default(TDest); }
我为什么不能做:
string dest = Gimme(5);
没有得到编译器错误:
error CS0411: The type arguments for method 'Whatever.Gimme<TSource,TDest>(TSource)' cannot be inferred from the usage. Try specifying the type arguments explicitly.
该5可作为推断int,但有编译器将不会/无法解决的返回类型的限制string。我在几个地方都读到 这是设计使然, 但没有真正的解释。我在某处读到它可能会在C#4中更改,但没有更改。
5
int
string
有谁知道为什么不能从通用方法中推断出返回类型?这是答案中最显而易见的问题之一吗?我希望不是!
这里的一般原则是类型信息仅从表达式的 内部 到 外部 “单向”流动。您给出的示例非常简单。假设在对某个方法进行类型推断时,我们希望类型信息流“双向”流动R G<A, R>(A a),并考虑一些产生以下疯狂现象:
R G<A, R>(A a)
N(G(5))
假设有十个不同的N重载,每个重载具有不同的参数类型。我们应该为R做出十个不同的推论吗?如果这样做的话,我们是否应该以某种方式挑选“最佳”的?
double x = b ? G(5) : 123;
应该推断出G的返回类型是什么?Int,因为条件表达式的另一半是int?还是加倍,因为最终这件事将要分配给加倍?现在也许您开始了解这种情况。如果您要说的是从外到内, 那么您走了多远 ?一路上可能会有 很多 步骤。看看当我们开始结合这些时会发生什么:
N(b ? G(5) : 123)
现在我们该怎么办?我们有十个N重载可供选择。我们说R是整数吗?它可以是int或int可隐式转换为的任何类型。但是,在那些类型中,哪些类型可以隐式转换为N的参数类型?我们是否为自己编写了一个小的prolog程序,并要求prolog引擎解决R可能满足的所有返回类型,以便满足N上的每个可能的重载,然后以某种方式选择最佳的返回类型?
(我不是在开玩笑;实际上,有些语言 确实 编写了一个小小的prolog程序,然后使用逻辑引擎来计算一切的类型。例如,F#的方式比C#的方式更复杂。Haskell的类型系统实际上是图灵完备的;您可以在类型系统中编码任意复杂的问题,然后要求编译器解决它们。正如我们将在后面看到的,C#中的重载解析也是如此- 您无法在C#中编码暂停问题像在Haskell中一样的类型系统,但是您可以将NP-HARD问题编码为重载解决问题。)( 请参见下文 )
这仍然是一个非常简单的表达。假设您有类似
N(N(b ? G(5) * G("hello") : 123));
现在,我们必须多次解决G的问题,可能还要解决多次N的问题,并且必须 结合起来 解决它们。我们有五个要解决的重载解决问题,公平地说, 所有 这些问题都应同时考虑其参数和上下文类型。如果N有十种可能性,那么N(N(…))可能有一百种可能性,而N(N(N(…)))可能有一百种可能性,您很快就会让我们解决这些问题很容易拥有数十亿种可能的组合,并使编译器非常慢。
这就是为什么我们有一个规则,即类型信息只能以一种方式流动。它可以防止这类鸡和鸡蛋的问题,在这种情况下,您既要尝试从内部类型确定外部类型,又要从外部类型确定内部类型,并导致各种可能性的组合爆炸。
请注意,类型信息确实对lambda双向流动!如果您说的N(x=>x.Length)那么确定,我们将考虑所有在参数中包含函数或表达式类型的N的可能重载,并尝试x的所有可能类型。可以肯定的是,在某些情况下,您可以轻松使编译器尝试数十亿种可能的组合,以找到有效的唯一组合。使通用方法能够做到的类型推断规则极其复杂,甚至让乔恩·斯凯特(Jon Skeet)感到紧张。此功能使过载分辨率为NP- HARD。
N(x=>x.Length)
使类型信息以双向方式传递给lambda,以使通用的重载解析正常有效地花费了我大约一年的时间。这是一个非常复杂的功能,我们只想绝对肯定会从这项投资中获得惊人的回报,就可以继续使用它。使LINQ正常工作是值得的。但是没有像LINQ这样的相对应的功能可以证明为使该功能正常工作而付出的巨大费用。
更新 :事实证明,您 可以 在C#类型的系统中编码任意困难的问题。C#具有具有一般矛盾性的名义上的一般子类型,并且已经表明,您可以使用一般类型定义来构建Turing Machine,并强制编译器执行该机器,从而可能会陷入无限循环。在我撰写此答案时,此类系统的不确定性是一个悬而未决的问题。有关详细信息,请参见https://stackoverflow.com/a/23968075/88656。