Reputation: 8997
I read the answers of those questions:
But I found out something surprising about the underlying type of discriminated unions:
type Union1 =
| A
| B
type Union2 =
| A
| B of int
[<EntryPoint>]
let main argv =
printfn "%A" (Union1.A.GetType())
printfn "%A" (Union1.B.GetType())
printfn "%A" (Union2.A.GetType())
printfn "%A" (Union2.B(32).GetType())
0
Program+Union1
Program+Union1
Program+Union2+_A
Program+Union2+B
Hence my question how I can discriminate a case based on the type when a case is empty?
Upvotes: 2
Views: 625
Reputation: 243041
There is no way to distinguish between two union cases with no parameters based on type, because their type in compiled .NET code is the same. You can see that this is the case by slightly tweaking your example:
type Union1 = A | B
Union1.A.GetType() = Union1.B.GetType() // Returns 'true'
The F# compiler compiles Union1
as a class with a numerical Tag
field. For cases with no additional parameters like A
and B
here, it will just create an instance of Union1
and set the Tag
field to 0
or 1
.
When you have a union case with additional parameters, then the compiler generates a new inherited class that then stores values of these parameters (which is why you get a different type for Union2.B
).
From the F# perspective, values of a discriminated union have the same type (even if the way DUs are compiled means that the type can sometimes be an inherited class), so there is no reason to expect that you would be able to distinguish cases based on a type - if you have a case where you need this, you should probably reconsider your approach.
Upvotes: 7