问题理解C#类型推断,如语言规范中所述
-
02-10-2019 - |
题
这 C#语言规范 描述第7.5.2节中的类型推断。有一个我不明白的细节。考虑以下情况:
// declaration
void Method<T>(T obj, Func<string, T> func);
// call
Method("obj", s => (object) s);
Microsoft和Mono C#编译器都正确推断 T
= object
, ,但是我对规范中算法的理解将产生 T
= string
然后失败。这是我理解的方式:
第一阶段
如果EI是匿名函数,则 显式参数类型推断 (§7.5.2.7)是从EI到TI制造的
⇒没有效果,因为Lambda表达式没有明确的参数类型。对?
否则,如果EI具有U型U,而Xi是值参数,则 较低的推理 是从u到ti制成的。
⇒第一个参数是静态类型的
string
, ,所以这添加了string
到下限T
, , 对?
第二阶段
全部 没有固定 类型变量XI不 取决于 (§7.5.2.5)任何XJ都是固定的(§7.5.2.10)。
⇒
T
没有固定;T
不依赖任何东西...所以T
应该修复,对吗?
§7.5.2.11修复
候选人类型UJ的集合开始为XI范围集中的所有类型集。
⇒ {
string
(下限)}然后,我们依次检查XI的每个界限:[...]对于XI的每个下限U,从候选集合中删除U的所有类型UJ的UJ。 [...
⇒没有从候选人组中删除任何内容,对吗?
如果在其余的候选类型UJ中,有一个唯一的类型V,从中有隐含的转换到所有其他候选类型,则XI已固定为V。
⇒由于只有一种候选人类型,这是真实的,因此XI固定为
string
. 。对?
那我要去哪里?
解决方案
更新:我今天早上对公共汽车的初步调查是不完整和错误的。第一阶段规范的文本是正确的。实施是正确的。
规格是错误的,因为它在第二阶段中犯了事件的顺序。我们应该指定我们进行输出类型推断 前 我们修复了非依赖性参数。
伙计,这东西很复杂。我对规格的这一部分重写的次数超出了我的记忆。
我以前曾经看过这个问题,我清楚地回想起进行修订,以使不正确的术语“类型变量”被“类型参数”替换为“类型变量”。 (类型参数不是存储位置,其内容可能会有所不同,因此将其称为变量是没有意义的。)我认为同时我指出订购是错误的。可能发生的可能是我们不小心在网络上运送了旧版本的规格。许多道歉。
我将与MADS合作以更新规格以匹配实现。我认为第二阶段的正确措辞应该这样做:
- 如果不存在未连接的类型参数,则类型推断成功。
- 否则,如果存在一个或多个参数EI具有相应的参数类型Ti,则具有TI类型的EI的输出类型至少包含一个未固定的类型参数XJ,而Ti类型的EI的输入类型都不包含任何未固定的类型参数XJ,然后从所有此类EI到Ti进行输出类型推断。
无论上一步是否实际上做出了推断,我们现在必须至少修复一个类型的参数,如下:
- 如果存在一个或多个类型的参数XI,以使XI未固定,并且XI具有一组非空的边界,并且XI不依赖于任何XJ,则每个此类XI均已固定。如果任何固定操作失败,则输入推理失败。
- 否则,如果存在一个或多个类型的参数XI,以使XI取消使用,并且XI具有一组非空的界限,并且至少有一个类型的参数XJ取决于XI,则每个此类XI均已固定。如果任何固定操作失败,则输入推理失败。
- 否则,我们将无法取得进步,并且存在未连接的参数。类型推理失败。
如果类型推断既不会失败也没有成功,则重复第二阶段。
这里的想法是,我们要确保该算法永远不会进入无限循环。在第二阶段的每一次重复中,它要么成功,失败或取得进步。它不可能比有类型参数要修复到类型的循环次数更多。
感谢您引起我的注意。