Общая функция 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 
Другие вопросы по тегам