通用F#功能:如何获取F#鉴别联盟的类型?

时间:2015-02-16 09:22:28

标签: generics f# discriminated-union

代码示例:http://www.tryfsharp.org/create/dutts/Generics.fsx

我的F#中有一些映射代码,它接受一个C#对象并将其包装在一个有区别的联合中。

module MyModule =
    type MappedThings =
        | DoThings of External.Things.DoThings

    type MappedStuff =
        | DoStuff of External.Stuff.DoStuff

因为我总是在我的区别联盟中使用相同的名称作为外部对象,我想尝试使我的映射代码通用以实现可伸缩性。这是我到目前为止所尝试的:

let toDomain<'T> external : 'T =
    let found = FSharpType.GetUnionCases(typeof<'T>) |> Seq.where (fun t -> t.Name = external.GetType().Name) |> Seq.head
    FSharpValue.MakeUnion(found, [| box external |]) :?> 'T  

我试图像这样使用它:

let testThings = toDomain<MyModule.MappedThings> doExternalThings
let testStuff = toDomain<MyModule.MappedStuff> doExternalStuff 

这适用于第一次调用,但如果我尝试将其用于MyModule.MappedStuff类型,则会抱怨

This expression was expected to have type DoThings but here has type DoStuff

我尝试使用静态解析的类型参数^ T,但是类型&lt; ^ T&gt;抱怨。

如果我能以某种方式通过&#34; Type&#34;我认为我可以让它工作。 (如果这是正确的术语,例如MyModule.Mapped)作为参数,但我不知道如何以编程方式获取。

有人可以帮忙吗?

1 个答案:

答案 0 :(得分:3)

我认为你为Makeunion的第二个参数引入的额外装箱会将类型推断抛出轨道,实际上,该函数不再是通用的。要么注释参数,要么删除box

let toDomain<'T> external : 'T =
    let found = FSharpType.GetUnionCases(typeof<'T>) |> Array.find (fun t -> t.Name = external.GetType().Name) 
    FSharpValue.MakeUnion(found, [| external |]) :?> 'T