我有一些强制使用数值范围的类型,并且我在单个项目的许多文件中使用它们。他们看起来像这样:
[<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表达式访问。
问题Why does the F# compiler fail with this infix operator?中已解决了此问题的原因。答案中提出的解决方案是使用F# signature files将类型设置为内部类型。这适用于该问题中OP的场景,在该场景中,运算符的使用仅限于同一文件中的类型。但是,我似乎找不到一种使它起作用的方法,因此可以从项目中的所有文件访问该操作符。如果我使用签名文件,则它在文件内起作用,但在文件间不起作用。
有什么办法可以使该类型在程序集内部,但是在我项目中的所有文件中可见吗?我想保留运算符,因为我正在使用像Seq.sum
这样的库函数,这些函数需要它们的求和类型。
答案 0 :(得分: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>]
使操作员可用于整个项目。