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

时间:2010-09-13 00:24:48

标签: c# language-features type-inference language-specifications

C# language specification 描述了第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且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。右


那我哪里出错?

1 个答案:

答案 0 :(得分:41)

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

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

男人,这个东西很复杂。我已经重新编写了规范的这一部分,而不是我记得的。

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

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

  
      
  • 如果不存在不固定的类型参数,则类型推断成功。
  •   
  • 否则,如果存在一个或多个参数Ei   相应的参数类型Ti就是这样   类型为Ti的Ei的输出类型包含至少一个未固定的   类型参数Xj,和   没有类型为Ti的Ei的输入类型包含任何未固定的类型   类型参数Xj,   然后从所有这样的Ei到Ti进行输出类型推断。
  •   
     

上一步是否真的做出了推断,我们   现在必须修复至少一个类型参数,如下所示:

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

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

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

感谢您引起我的注意。