F#编译器要求项目引用,但方法是私有的。

10

F#编译器给出错误提示,说我必须添加一个项目引用,因为我使用的类型具有在该项目中存在的方法参数。 但是,这个方法是私有的!

我的项目结构如下:

程序 -> 库 -> 子库

子库 包含以下内容:

namespace SubLibrary

type Widget = { Value: int }

图书馆包含这些内容:

namespace Library

open SubLibrary

type Banana =
    { Value: int }

    member private x.TakeWidget (w: Widget) = ()

程序包含此内容:

open Library

[<EntryPoint>]
let main argv = 
    printfn "%A" argv

    let banana = { Value = 42 }
    0

我收到了这个错误:

error FS0074:
The type referenced through 'SubLibrary.Widget' is defined in an assembly that is not referenced.
You must add a reference to assembly 'SubLibrary'

但是TakeWidget方法是私有的

我尝试将Banana改为类而不是记录,但这没有任何区别。

作为一个实验,我创建了一个C#版本的Library,名为CLibrary

using SubLibrary;

namespace CLibrary {
    public class CBanana {
        int m_value;

        public CBanana(int value) {
            m_value = value;
        }

        private void TakeWidget(Widget w) {
        }
    }
}

然后我将Program更改为使用CBanana而不是Banana

open Library

[<EntryPoint>]
let main argv = 
    printfn "%A" argv

    let banana = CBanana 42
    0

现在我没有错误了。实际上,使用C#,我可以将该方法设置为public,只要我不尝试编译调用它,就不会出错。

为什么编译器坚持要我添加对SubLibrary的引用?当然,我可以按照它告诉我的去做,过上安静的生活,但是SubLibrary是Library的私有实现细节,不应该暴露给Program。

2个回答

2

实际上,当我使用类而不是记录时,它可以解决问题(F# 3.1):

type BananaClass (value:int) = 
    member private x.TakeWidget (w: Widget) = ()
    member x.Value = value

您可以通过记录来解决这个问题 - 您需要将私有成员移动到单独的模块中,并将其作为类型扩充:

type Banana = { Value: int }

module Ext =
    type Banana with
        member x.TakeWidget (w: Widget) = ()

编译器在你打开Ext模块之前不会抱怨缺少依赖项。
我不知道编译器为什么一开始就抱怨。可能是其中一个怪癖。我在生成的IL中没有发现任何严重可疑的东西(除了一个令人惊讶的事实,即F#编译器将私有和内部成员都标记为内部的IL - 在这里这种情况并无影响)。

我也在使用F# 3.1(VS 2013)。如果Banana是一个类,你可以编译调用构造函数,但是如果你尝试访问公共的Value属性,那时候你会得到错误。在我的情况下,我需要这个方法是内置的,因为它需要使用反射来发现,所以可选的扩展对我来说不好。谢谢你的回复。 - bananasareyellow
有点不出所料的是,规范说明了“所有非公共实体的CLI编译形式均为internal”。 - kaefer

1

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