问题
Code example: http://www.tryfsharp.org/create/dutts/Generics.fsx
I have some mapping code in my F# which takes a C# object and wraps it in a discriminated union.
module MyModule =
type MappedThings =
| DoThings of External.Things.DoThings
type MappedStuff =
| DoStuff of External.Stuff.DoStuff
As I always use the same name in my discriminated union as the external object I would like to try to make my mapping code generic for scalability. This is what I've tried so far:
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
I am trying to use it like this:
let testThings = toDomain<MyModule.MappedThings> doExternalThings
let testStuff = toDomain<MyModule.MappedStuff> doExternalStuff
This works fine for the first call, but if I try to use it for MyModule.MappedStuff type it complains with
This expression was expected to have type DoThings but here has type DoStuff
I've tried using statically resolved type parameters, ^T, but the typeof<^T> complains.
I was thinking I could get this to work if I could somehow pass the "Type" (if that's the correct term, e.g. MyModule.Mapped) as a parameter but I don't know how to get that programmatically.
Can anyone help?
回答1:
I think that the additional boxing that you introduce for the 2nd parameter of Makeunion
throws the type inference off the track and in fact, the function isn't generic anymore. Either annotate the argument or remove the 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
来源:https://stackoverflow.com/questions/28538106/generic-f-function-how-to-get-the-type-of-an-f-discriminated-union