ПРИМЕЧАНИЕ здесь есть оговорка.См. ОБНОВЛЕНИЕ ниже.
Похоже, что объединения объединяются как вложенные классы типа объединения (имя типа: FSI_0006+Shape+Square
).Поэтому, учитывая экземпляр типа объединения, достаточно проверить тип экземпляра с помощью obj.GetType()
.
let expect (someShape:'T) (someUnionCase:'T) =
if (someShape.GetType() <> someUnionCase.GetType()) then failwith "type not compatible"
type Shape =
| Circle of int
| Square of int
| Rectangle of ( int * int )
let myShape = Shape.Square 12
printfn "myShape.GetType(): %A" (myShape.GetType())
expect myShape (Shape.Circle 5)
Это выводит:
myShape.GetType(): FSI_0006+Shape+Square
System.Exception: type not compatible
at Microsoft.FSharp.Core.Operators.FailWith[T](String message)
> at FSI_0006.expect[T](T someShape, T someUnionCase)
at <StartupCode$FSI_0006>.$FSI_0006.main@()
Stopped due to error
Я просто не знаю, считается ли этот подход зависимым от реализации, т. Е. Некоторые платформы / среды выполнения реализуют это по-разному, так что типы двухразличные объекты падежа одинаковы.
ОБНОВЛЕНИЕ
ОК. Я обнаружил, что вышеописанное не работает для типа объединения с делами, которые не принимают параметров.В этом случае реализация вариантов отличается, и .GetType()
всегда дает тип объявления типа объединения.Приведенный ниже код демонстрирует это:
type Foo = A|B|C
type Bar = X|Y|Z of int
let getType (x:obj) = x.GetType()
let p (x:obj) = printfn "%A" x
A |> getType |> p
B |> getType |> p
C |> getType |> p
X |> getType |> p
Y |> getType |> p
Z 7 |> getType |> p
Это дает:
FSI_0004+Foo
FSI_0004+Foo
FSI_0004+Foo
FSI_0004+Bar+_X
FSI_0004+Bar+_Y
FSI_0004+Bar+Z
Более общая альтернатива, как упоминалось в другом ответе, заключалась бы в преобразовании экземпляров case в теги:
open Microsoft.FSharp.Reflection
// more general solution but slower due to reflection
let obj2Tag<'t> (x:obj) =
FSharpValue.GetUnionFields(x, typeof<'t>) |> fst |> (fun (i: UnionCaseInfo) -> i.Tag)
[A;B;C;A] |> List.map obj2Tag<Foo> |> p
[X;Y;Z 2; Z 3; X] |> List.map obj2Tag<Bar> |> p
Это дает:
[0; 1; 2; 0]
[0; 1; 2; 2; 0]
Это должно быть значительно медленнее, если работать с большим количеством объектов, так как оно сильно зависит от отражения.