我在C#(LibC)和F#(LibF)代码使用的公共库(LibRoot)中定义了一个带有度量单位的记录类型 .
然后我在F#库(LibF)消耗的C#库(LibC)中编写了一个公共API . 但是任何时候我试图将一个对象传递给这个API F#抱怨它必须有一个度量单位 .
//LibRoot - F#
type Vec2<[Measure] 'u> = {
X : int
Y : int
}
//LibC - C#
public static class Funcs
{
public void DoWork(Vec2 vec) { //no measure needed in C#
....
}
}
//LibF - F#
open LibC
let myVec : Vec2<1> = { X = 123; Y = 456 }
DoWork(myVec) //FS0001
error FS0001: Type mismatch. Expecting a 'Vec2' but given a 'Vec2<1>' The tuples have differing lengths of 0 and 1
我试过了:
-
Vec2<1>
:FS0001 -
Vec2<0>
:类型中的文字无效 -
Vec2<()>
:类型中出现意外')' -
Vec2<_>
:FS0001 -
Vec2<unit>
:预期的计量单位,而不是类型 -
(Vec2) myVec
:没有可用于类型'Vec2<' u>的构造函数
Does anybody know a way to construct a measured record type in an interop friendly way?
2 回答
正如评论中所提到的,度量单位是F#-only功能,在编译的.NET代码中没有任何表示,因此当您使用C#中的单元注释类型时,它将显示为没有单位的类型 .
已编译的C#代码将不包含特殊的F#元数据,以指示这是一个单元注释类型,因此引用您的C#库的F#编译器不会将其识别为单元注释类型 . 可以说,F#编译器可能更聪明并想出来(因为它可以发现
Vec2
类型最初来自F#) .我不认为有一种安全的方法可以将未测量的
Vec2
转换为测量的Vec2<_>
,但使用unbox
的不安全转换将在运行时工作:我不认为有一种方法可以在F#代码中明确引用类型
Vec2
(没有度量),但unbox
推断类型罚款 . 这不是很好,所以如果你经常需要这种转换,最好重新设计你的库,以便C#使用一个没有单位的单独类型 .托马斯的回答是正确的 . 我将与后人分享我的解决方法 .
我的衡量单位是
我介绍了'concrete'记录类型,可以转换为
Vec2<>
用于互操作 . 例如我将它们转换为Vec2来执行数学运算,但是对公共API使用“具体”类型 . 有额外的类型有点烦人,但它的工作原理 .