Общая функция F#: Как получить Тип F# Дискриминационного Союза?
Пример кода: 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, но тип<^ T> жалуется.
Я думал, что мог бы заставить это работать, если бы я мог как-то передать "Тип" (если это правильный термин, например, MyModule.Mapped) в качестве параметра, но я не знаю, как получить это программно.
Кто-нибудь может помочь?
1 ответ
Я думаю, что дополнительный бокс, который вы вводите для 2-го параметра 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