在程序集的所有文件中,是否可以对内部类型进行F#运算符重载?

4

我有一些强制数值范围的类型,我在单个项目中的许多文件中使用它们。它们看起来像这样:

[<Struct>]
type NonNegativeMoney =
    new(x) =
        if x < 0m then invalidArg "x" "Ruh-roh..."
        { Value = x }
    val Value : decimal
    static member (+) (x: NonNegativeMoney, y: NonNegativeMoney) = NonNegativeMoney(x.Value + y.Value)

我现在希望将这些类型改为内部类型,并仅保留我的OO类型模型为公共类型。然而,当我将这些类型转换为内部类型时,会出现以下编译器错误:

成员或对象构造函数 'op_Addition' 不是公共的。私有成员只能从声明类型内访问。受保护成员只能从扩展类型访问,不能从内部 lambda 表达式访问。

这个问题已经在问题“为什么F#编译器会因此中缀运算符而失败?”中得到了解决。回答中提出的解决方案是使用F#签名文件将这些类型变为内部类型。这在该问题中的类型仅限于同一文件中使用操作符的情况下可以解决。但是,我似乎找不到一种使其在项目中所有文件中都可以访问的方法。如果我使用签名文件,则在文件内有效,但在文件间无效。
有没有办法使这些类型成为程序集内部类型,但在项目的所有文件中都可见?我想保留这些操作符,因为我正在使用像Seq.sum等库函数需要这些操作符的类型进行求和。

你尝试过使用 InternalsVisibleTo 属性进行注释吗? - s952163
2
@s952163 我需要注释什么?我认为 InternalsVisibleTo 是用于跨程序集使用的。我正在尝试在同一程序集中使用运算符。请您详细说明一下? - bentayloruk
我明白了。您想注释程序集属性,类似这样 [<assembly: InternalsVisibleTo("NonNegativeMoney")>],您可以尝试一下,但正如您所说,您的用例略有不同。 - s952163
1
InternalsVisibleTo 属性在构造函数中需要一个程序集名称,因此我不能使用 NonNegativeMoney。也许我可以将数字类型提取到一个新的程序集中,使用签名文件使其成为内部元素(如其他答案所述),然后添加 InternalsVisibileTo 属性,并引用我的主程序集。但这种方法感觉很不好。希望有更好的解决方案。 - bentayloruk
我在之前的评论中提出的解决方案,对于运算符仍然不起作用。我将类型移动到新的程序集中,添加了sig文件(使其内部可见),然后使用了InternalsVisibleTo,但现在我得到了BlahBlahType.fs(10, 10): [FS0001] The member or object constructor 'op_Addition' is not public. Private members may only be accessed from within the declaring type. Protected members may only be accessed from an extending type and cannot be accessed from inner lambda expressions. 我可以创建该类型的值(所以我知道IVT正在工作),但是操作使用仍然失败。 - bentayloruk
1个回答

0
你可以在模块中定义重载,而不是在类型内部:
[<Struct>]
type internal NonNegativeMoney =
    new(x) =
        if x < 0m then invalidArg "x" "Ruh-roh..."
        { Value = x }
    val Value : decimal

let internal (+) (x: NonNegativeMoney) (y: NonNegativeMoney) = NonNegativeMoney(x.Value + y.Value)

...但这将覆盖正常的 (+) 运算符,这可能是你排除它的原因。使用自定义运算符(如 ++)可能是一个合理的折衷方案。

您可以通过标记模块 [<AutoOpen>]使运算符对整个项目可用。


谢谢你的回答。实际上我没有考虑过这种方法,但我认为它并不能解决我的问题,因为我正在使用像sumsumBy这样需要类型上的op_Addition函数的库函数。我会编辑问题以包含这个细节。 - bentayloruk

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