理解C#类型推断在语言规范中的描述存在问题

62

C#语言规范在第§7.5.2节中描述了类型推断。其中有一个细节我不太明白。考虑以下情况:

// declaration
void Method<T>(T obj, Func<string, T> func);

// call
Method("obj", s => (object) s);

微软和Mono C#编译器都正确地推断出T = object,但是根据规范中的算法,我的理解会导致T = string,然后失败。以下是我的理解: 第一阶段 - 如果Ei是匿名函数,则从Ei到Ti进行显式参数类型推断(§7.5.2.7)。 ⇒没有影响,因为lambda表达式没有显式参数类型。对吗? - 否则,如果Ei具有类型U并且xi是值参数,则从U到Ti进行下限推断。 ⇒第一个参数的静态类型为string,因此这将把string添加到T的下限中,对吗? 第二阶段 - 所有不依赖于任何Xj的未固定类型变量Xi都被固定(§7.5.2.10)。 ⇒T未固定;T不依赖于任何东西...所以T应该被固定,对吗? §7.5.2.11 固定 - 候选类型集合Uj最初为Xi边界集合中的所有类型的集合。 ⇒{ string(下限) } - 然后,我们依次检查Xi的每个边界:[...]对于Xi的每个下限U,从U中没有隐式转换到Uj的所有类型Uj都将从候选集合中删除。 [...] ⇒不会从候选集合中删除任何内容,对吗? - 如果在剩余的候选类型Uj中有一个唯一的类型V,从这个类型V到所有其他候选类型都有隐式转换,则Xi被固定为V。 ⇒由于只有一个候选类型,这是真实的,因此Xi被固定为string。对吗?
那我错在哪里了?

19
嗯...嗯...你可能发现了一个漏洞,它可能存在于规范中或实现过程中。我会在周一回到办公桌上查看它;现在我得去做晚饭了。 - Eric Lippert
6
@Eric - 好的,我们会允许你吃晚饭,但我们需要在周一早上得到迅速的答复。 :) - ChaosPandion
7
我头疼了。 - Rusty
@Eric Lippert:一般来说,报告规范中明显的错误应该在哪里?例如,“第二阶段”引用了错误的章节号进行“修复”,或者在“修复”下面写着“每个边界”,而应该是“每个确切的边界”等。 - Timwi
2
@Timwi:那就是 Eric Lippert 的蝙蝠信号了。开个玩笑!我认为正确的地方是:http://connect.microsoft.com/VisualStudio - jasonh
3
这是一个非常好的问题!如果可以的话,我会给它加100分。 - Alastair Pitts
1个回答

41

更新:我今早在公交车上对此进行的初步调查是不完整和错误的。第一阶段规范的文本是正确的,实现也是正确的。

规范有误,因为它在第二阶段中将事件顺序弄错了。我们应该规定在修复非相关参数之前进行输出类型推断。

这些东西很复杂。我已经重写了规范的这部分内容太多次以至于无法记住。

我以前见过这个问题,并且清楚地记得做出了修改,以便用“类型参数”替换了不正确的术语“类型变量”。(类型参数不是可以改变其内容的存储位置,所以称它们为变量是没有意义的。)我认为同时我还注意到顺序是错误的。可能发生的情况是我们意外地在网上发布了旧版本的规范。非常抱歉。

我会与Mads一起努力更新规范以匹配实现。我认为第二阶段的正确措辞应该像这样:

  • 如果不存在未固定的类型参数,则类型推断成功。
  • 否则,如果存在一个或多个具有相应参数类型Ti的参数Ei,使得Ei的输出类型与Ti的类型至少包含一个未固定的类型参数Xj,并且Ei的输入类型中没有一个包含任何未固定的类型参数Xj,则从所有这样的Ei到Ti进行输出类型推断。

无论上一步是否实际进行了推断,现在我们都必须至少固定一个类型参数,方法如下:

  • 如果存在一个或多个类型参数Xi是未固定的,并且Xi有一个非空的边界集,并且Xi不依赖于任何Xj,则将每个Xi固定。如果任何固定操作失败,则类型推断失败。
  • 否则,如果存在一个或多个类型参数Xi是未固定的,并且Xi有一个非空的边界集,并且
如果存在至少一个依赖于Xi的类型参数Xj,则每个Xi都被固定。如果任何固定操作失败,则类型推断失败。否则,我们无法取得进展并且有未固定的参数。类型推断失败。如果类型推断既不失败也不成功,则重复第二阶段。这里的想法是确保算法永远不会陷入无限循环。在第二阶段的每次重复中,它要么成功,要么失败,要么取得进展。它不可能循环的次数超过要固定到类型的类型参数数量。感谢您提供这些信息。

好的,我尝试了各种情况,这个版本似乎可以工作。我现在会接受这个答案,但如果我遇到更多问题,我会回来的... ☺ - Timwi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接