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

Tim*_*mwi 62 c# language-features type-inference language-specifications

C#语言规范描述键入第7.5.2节推断.其中有一个我不明白的细节.考虑以下情况:

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

// call
Method("obj", s => (object) s);
Run Code Online (Sandbox Code Playgroud)

Microsoft和Mono C#编译器都正确推断T= object,但我对规范中算法的理解会产生T= string然后失败.以下是我的理解:

第一阶段

  • 如果Ei是匿名函数,则从Ei到Ti 进行显式参数类型推断(第7.5.2.7节)

    ⇒没有效果,因为lambda表达式没有明确的参数类型.对?

  • 否则,如果Ei具有类型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中存在唯一的类型V,其中存在对所有其他候选类型的隐式转换,则Xi被固定为V.

    ⇒因为只有一种候选类型,所以这是真实的,所以Xi固定为string.对?


那我哪里错了?

Eri*_*ert 41

更新:我今天早上对公交车的初步调查是不完整和错误的.第一阶段规范的文本是正确的.实施是正确的.

规范是错误的,因为它在第二阶段得到错误的事件顺序.我们应该修复非依赖参数之前指定我们进行输出类型推断.

伙计,这东西很复杂.我已经重新编写了规范的这一部分,而不是我记得的.

我以前见过这个问题,我清楚地记得做出修改,以便用"类型参数"替换不正确的术语"类型变量".(类型参数不是内容可以变化的存储位置,因此将它们称为变量是没有意义的.)我想同时我注意到排序错误.可能发生的事情是我们不小心在网上发布了旧版本的规范.很多道歉.

我将与Mads合作以更新规范以匹配实现.我认为第二阶段的正确措辞应该是这样的:

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

无论前一步是否实际进行了推断,我们现在必须修复至少一个类型参数,如下所示:

  • 如果存在一个或多个类型参数Xi使得Xi不固定,并且Xi具有非空的边界集合,并且Xi不依赖于任何Xj,则每个这样的Xi是固定的.如果任何修复操作失败,则类型推断失败.
  • 否则,如果存在一个或多个类型参数Xi使得Xi不固定,并且Xi具有非空边界集,并且存在至少一个取决于Xi的类型参数Xj,则每个这样的Xi是固定的.如果任何修复操作失败,则类型推断失败.
  • 否则,我们无法取得进展,并且存在不固定的参数.类型推断失败.

如果类型推断既未失败也未成功,则重复第二阶段.

这里的想法是我们要确保算法永远不会进入无限循环.在第二阶段的每次重复中,它都会成功,失败或取得进展.它不可能循环多于类型参数来修复类型.

谢谢你引起我的注意.