完全限定名称,带有导入声明的非限定名称解析不同

时间:2012-01-04 19:26:00

标签: f#

这有效

open System
let f = Action(fun () -> Unchecked.defaultof<_>)

但是这个

let f = System.Action(fun () -> Unchecked.defaultof<_>)

产生编译错误

  

存在多种类型,称为“Action”,采用不同数量的通用参数。提供类型实例化以消除类型解析的歧义,例如'动作及LT; ,_,,_,,_&GT;'。

我知道我可以通过添加类型参数占位符(System.Action<_>(...))来修复它,但是知道为什么它们的行为不同?

修改

在规范第14.1.9节中找到了这个:

  

当打开模块或名称空间声明组F时,项目将添加到名称环境中,如下所示:

     
      
  • 将类型添加到 TypeNames 表中。如果类型具有CLI错误的通用名称,例如List'1,则会在ListList'1下添加一个条目。
  •   

是否为完全限定类型(省略了类型参数)复制了此行为?它似乎不是这样。

1 个答案:

答案 0 :(得分:4)

我同意@James这与Connect上提交的错误有关,但我认为这是一个略有不同的情况。无论如何,我认为这不是预期的行为。你可以在 microsoft dot com 上向 fsbugs 报告吗?

无论如何 - 我做了一些调试,这是我到目前为止所发现的:

编译器似乎使用不同的代码路径来解析名称Action和名称System.Action。解析另一个时,它会搜索所有已加载的模块(即程序集)以查找名为System.Action的类型(请参阅开源版本nameres.fs file中的ResolveLongIndentAsModuleOrNamespaceThen函数)。

这会找到Action的两个定义(mscorlib中的一个和System.Core中的另一个)。我认为问题来自这样一个事实:名称解析简单地遍历结果 - 它找到第一个(来自System.Core),它没有可用的重载(因为它的范围是Action<_,_,_,_,_>到具有约15个类型参数的版本)。找到此类型后,它会报告错误,甚至不会查看是否有其他类型(在另一个程序集中)可以使用。

如果您不引用系统程序集,那么F#编译器可以很好地解决重载问题。运行不带参数的编译器会引用默认的程序集,因此不起作用:

fsc test.fs 

但是如果我添加--noframework标志,那么它会毫无问题地编译:

fsc --noframework test.fs