我已经在公共库(libroot)中定义了一个记录类型,该记录类型均由C#(libc)和F#(libf)代码使用。
i然后在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
错误FS0001:键入不匹配。期望一个" vec2",但给出了" vec2&lt; 1>"。不同的长度为0和1
我尝试过:
-
Vec2<1>
:FS0001 -
Vec2<0>
:类型中无效的文字 -
Vec2<()>
:意外')' -
Vec2<_>
:FS0001 -
Vec2<unit>
:预期的度量单位,不是类型 -
(Vec2) myVec
:没有可用于'vec2&lt;'u>
的构造函数
是否有人知道一种以互惠方式构造测量的记录类型的方法?
如注释中所述,度量单位是f# - 仅在编译的.NET代码中没有表示的功能,因此当您使用C#的单位声明类型时,它将显示为没有单位的类型。
编译的C#代码将不包含特殊的F#meta-data,以表明这是单位声明的类型,因此F#编译器引用您的C#库不会将其识别为单位声明类型。可以说,F#编译器可以更聪明并弄清楚这一点(因为它可以确定Vec2
类型最初来自F#)。
我认为没有一种安全的方法可以将未测量的Vec2
转换为测量的Vec2<_>
,但是使用unbox
的不安全转换将在运行时起作用:
let v : LibRoot.Vec2<1> = { LibRoot.Vec2.X = 1; Y = 2 }
LibCs.Funcs.DoWork(unbox v)
我认为在F#代码中明确指出Vec2
类型(无需测量)的方法没有一种方法,但是unbox
不断添加该类型的罚款。这不是很好,因此,如果您经常需要此转换,则最好重新设计库,以便C#使用没有单位的单独类型。
tomas的答案是正确的。我将分享我的解决方法。
我的度量单位是
[<Measure>] type Absolute
[<Measure>] type Relative
我引入了可转换为Vec2<>
的"混凝土"记录类型。例如
type Offset2 = {
X : int
Y : int
}
with
static member ofVec (vec : Vec2<Relative>) : Offset2 = { X = vec.X; Y = vec.Y }
static member toVec (off: Offset2) : Vec2<Relative> = { X = off.X; Y = off.Y }
我将它们转换为VEC2以执行数学,但将"混凝土"类型用于公共API。拥有额外的类型有点烦人。