Reputation: 1401
I have the following discriminated union with a member function where I want to return the unboxed type:
type ModelData =
| Double of double
| UInt32 of uint32
| UInt16 of uint16
| Byte of byte
| Int32 of int32
| String of string
| Bit of Bit
member inline this.Value : 'a =
match this with
| Double x -> x
| UInt32 x -> x
| UInt16 x -> x
| Byte x -> x
| Int32 x -> x
| String x -> x
| Bit x -> x
The error is that the member 'this.Value' doesn't return the same type for each branch. Is this possible?
Edit #1
I have a Database defined as follows which uses this ModelData
type:
module Database =
type Drecord =
{ Value: ModelData}
type Db = Dictionary<string, Drecord>
So I have a database full of values, then I take some of these values and generate a JSON string using sprintf.
sprintf "{\"General\":{\"Example\":%.3f}}" value //where value is of type ModelData
This currently does not work since sprintf requires a float
and not a ModelData
. So original I thought I could call a function to safely convert to that type (hence the this.Value
member). I've got this to work by having this.Value
instead return a string, and having only %s
in my sprintf format string.
So this works:
sprintf "{\"General\":{\"Example\":%s}}" value.Value
Is there a better way to solve this?
Upvotes: 0
Views: 158
Reputation: 243041
I'm not sure I understand what are you trying to do. If you define a discriminated union, then the value can be either of the cases and when you want to use a value of your ModelData
type, you'll need to pattern match on it in order to decide what kind of value you have.
If you add a way of getting a value that works only for one specific case (e.g. when the value is a float
), you are losing all the safety that discriminated unions give you. So, I think that doing what you're asking for is most likely going to be a bad idea.
That said, you can define a member GetValue<'a>
that can be called to extract value of a specific type using the unbox
function:
type ModelData =
| Double of double
| UInt32 of uint32
| UInt16 of uint16
member inline this.GetValue<'a>() : 'a =
match this with
| Double x -> unbox<'a> x
| UInt32 x -> unbox<'a> x
| UInt16 x -> unbox<'a> x
let v = Double 1.23
v.GetValue<float>()
This will, of course, throw an InvalidCastException
if you call it with the wrong type argument, e.g. v.GetValue<int>()
in the above case. Also note that this needs to be a method so that you can make it generic.
Upvotes: 2