Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do you get the Discriminated Union Type from a Case instance?

Given these two Discriminated Unions I'd like to get the DeclaringType from a case instance.

type SingleCaseUnion =
    | One

type MultiCaseUnion =
    | Two
    | Three

An example for each case would be as follows:

getDiscriminatedUnionType One = typeof<SingleCaseUnion> // true

getDiscriminatedUnionType Three = typeof<MultiCaseUnion> // true

My first attempt was to get the case type and get it's base class, this works because in F# a subtype is created for each case.

MultiCaseUnion.Two.GetType().BaseType = typeof<MultiCaseUnion> // true

However, for a single case union this doesn't work because no nested types are created.

SingleCaseUnion.One.GetType().BaseType = typeof<SingleCaseUnion> // false

My second attempt, which aimed to get a more robust solution was to use the FSharp Reflection helpers.

FSharpType.GetUnionCases(unionValue.GetType()).First().DeclaringType

This does work for all cases but it has to generate UnionCaseInfo instances for each case which seems somewhat unnecessary.

Is there Something built in that I may have missed? Something like:

FSharpValue.GetUnionFromCase(SingleCaseUnion.One)
like image 776
Daniel Little Avatar asked Dec 21 '16 04:12

Daniel Little


1 Answers

How about

open FSharp.Reflection
type FSharpType =
    static member GetUnionType t =         
        let ownType = t.GetType()
        assert FSharpType.IsUnion(ownType)
        let baseType = ownType.BaseType        
        if baseType = typeof<System.Object> then ownType else baseType

Test:

(FSharpType.GetUnionType MultiCaseUnion.Three).Name //MultiCaseUnion

(FSharpType.GetUnionType SingleCaseUnion.One).Name //SingleCaseUnion
like image 129
Asti Avatar answered Jan 18 '23 20:01

Asti