我正在使用OpenTK及其数学库,但不幸的是,矢量类没有通用接口。例如,Vector2,3和4都具有相同的静态方法SizeInBytes
http://www.opentk.com/files/doc/struct_open_t_k_1_1_vector3.html#ae7cbee02af524095ee72226d842c6892
现在我可以重载大量不同的构造函数,但我认为应该可以通过类型约束解决这个问题。
我正在阅读http://msdn.microsoft.com/en-us/library/dd233203.aspx,我发现了这个
type Class4<'T when 'T : (static member staticMethod1 : unit -> 'T) > =
class end
现在我自己尝试了,但我无法正确使用语法。
type Foo<'T when 'T: (static member SizeInBytes: unit -> int)>(data: 'T []) =
member this.GetBytes() = 'T.SizeInBytes()
let f = Foo([|new Vector3(1.0f,1.0f,1.0f)|])
f.GetBytes()
你能发现问题吗?
编辑:
VS2012抱怨此行'T.SizeInBytes() //Unexpected symbol or expression
和T.SizeInBytes()
也无效。
EDIT2:
我做了一个不涉及外部库的例子
type Bar() =
static member Print() = printf "Hello Foo"
type Foo<'T when 'T: (static member Print: unit -> unit)>(data: 'T []) =
member this.Print() = 'T.Print()
let b1 = Bar()
let f = Foo([|b1|])
f.Print()
答案 0 :(得分:6)
调用由成员约束保证的事物的正确语法有点模糊:
type Foo< ^T when ^T: (static member SizeInBytes: unit -> int)>(data: ^T []) =
member inline this.GetBytes() =
(^T : (static member SizeInBytes : unit -> int) ())
请注意,'T
必须更改为“静态解析的类型变量”^T
- 请参阅F# spec中的词汇表。
您不能调用由普通类型变量的约束指定的成员,因为.NET框架不支持它,因此F#必须将它们编译掉。如果我们尝试在'T
中使用GetBytes
,则会出现语法错误。
我认为MSDN文档通过给出'T
的示例有点误导,因为尽管您可以编写它们提供的类型,但您永远不能使用约束。
如果查看Class4
示例的IL代码,则约束实际上已经消失:
.class nested public auto ansi serializable Class4`1<T>
extends [mscorlib]System.Object
这是有道理的,因为必须为.NET删除成员约束。具有type Foo
类型变量的^T
也是如此。
另请注意,与所有inline
F#函数一样,您只能通过F#代码静态调用它,以便编译器可以在调用站点内联定义。
如果您尝试从C#代码或通过反射调用它,它将抛出异常。如果您尝试,您的代码将在运行时失败。
通常使用.NET不支持的F#约束是一项棘手的工作,所以如果可能的话,我会明确指出。
编辑:根据(a)我的进一步实验(b)Gene Belitski的答案和(c)idjarn关于inline
函数的评论,我已经大大更新了我的原始答案,错误地说这是不可能的。总是被编译到引发异常的IL。
答案 1 :(得分:4)
type Bar() =
static member SizeInBytes() = 42
type Foo< ^T when ^T: (static member SizeInBytes: unit -> int)>(data: ^T []) =
member inline this.GetBytes () = (^T : (static member SizeInBytes : unit -> int) ())
let result = (Foo([|Bar()|]).GetBytes())
val result : int = 42