我正在使用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
Run Code Online (Sandbox Code Playgroud)
现在我自己尝试了但是我无法正确使用语法.
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()
Run Code Online (Sandbox Code Playgroud)
你能发现问题吗?
编辑: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()
Run Code Online (Sandbox Code Playgroud)
调用由成员约束保证的事物的正确语法有点模糊:
type Foo< ^T when ^T: (static member SizeInBytes: unit -> int)>(data: ^T []) =
member inline this.GetBytes() =
(^T : (static member SizeInBytes : unit -> int) ())
Run Code Online (Sandbox Code Playgroud)
请注意,'T
必须将其更改为"静态解析的类型变量" ^T
- 请参阅F#规范中的术语表.
您不能调用由普通类型变量的约束指定的成员,因为.NET框架不支持它,因此F#必须将它们编译掉.这是一个语法错误,如果我们尝试使用'T
的GetBytes
替代.
我认为MSDN文档通过给出一个例子有点误导'T
,因为尽管你可以编写它们给出的类型,但你永远不能使用约束.
如果您查看Class4
示例的IL代码,则约束实际上已消失:
.class nested public auto ansi serializable Class4`1<T>
extends [mscorlib]System.Object
Run Code Online (Sandbox Code Playgroud)
这是有道理的,因为必须为.NET删除成员约束.同样是真正的type Foo
与^T
类型的变量.
另请注意,与所有inline
F#函数一样,您只能通过F#代码静态调用它,以便编译器可以在调用站点内联定义.
如果您尝试从C#代码或通过反射调用它,它将抛出异常.如果您尝试,您的代码将在运行时失败.
通常使用.NET不支持的F#约束是一件棘手的事情,所以如果可能的话,我会明确指出.
编辑:根据(a)我的进一步实验(b)Gene Belitski的答案和(c)idjarn的评论,inline
函数总是被编译到IL抛出一个,我已经大大更新了我的原始答案,错误地说这是不可能的.例外.