在F#中,您可以执行 black-magic voodoo 1 并执行静态类型约束以确保仅在具有成员约束的类型上调用函数。例如:
module Collection
let inline init s =
let collection = new ^t()
let add e = (^t : (member Add : 'a -> unit) collection, e)
Seq.iter add s
collection
可以在Add<'a>
具有签名'a -> unit
的类型中调用此函数。
用法:
let a:List<_> = Collection.init {1..10}
let b:SynchronizedCollection<_> = Collection.init {1..10}
a |> Seq.iter (fun x -> printf "%A " x)
b |> Seq.iter (fun x -> printf "%A " x)
输出:
1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10
我有兴趣在C#应用程序中利用这种功能,但不知道尝试这个时我会遇到什么样的陷阱或麻烦。
为了避免X-Y问题,我有一个WCF生成的客户端,它是一个被手动编辑的混乱程序。不使用它不是原因的选项。许多类型具有相同名称但具有不同类型且没有共同类型的成员属性,因此我对这种类型的通用约束感兴趣。
F#中的此功能是否可以解决我的问题?这是如何实现的?我知道C#不能做这样的事情......
1 不是真的,我只是不知道怎么回事。
答案 0 :(得分:3)
在F#中,静态成员约束(这个voodoo的名称)是通过每次调用init
函数的代码内联并为每个函数生成专用代码来实现的。使用
通常,.NET泛型约束不足以表达成员约束,因此无法直接映射到普通的.NET泛型约束。
当你写:
let a:List<_> = Collection.init {1..10}
let b:SynchronizedCollection<_> = Collection.init {1..10}
编译器基本上将Collection.init
替换为函数体,它将使用静态成员约束替换使用具体类型的具体Add
方法调用的调用。如果调用出现在无法确定具体类型的通用函数中,则不允许调用。
我认为您当然可以使用F#和静态成员约束来简化代码的工作,其中许多类型共享属性而没有任何更深层次的关系。但是,静态成员约束是特定于F#的,并且无法使用它们来定义辅助函数,然后可以从C#调用它们。您必须在F#中编写更大部分的客户端(并且可能会暴露出完全隐藏基础类型的漂亮干净的API)。