I have an enum type with the flags attribute:
[<Flags>]
type StatusWord =
| DATAPROCESS = 0b0000000001
| ERRORPRESENT = 0b0000000010
| CHECKSUMERROR = 0b0000000100
| PACKETSIZEERROR = 0b0000001000
| TIMEOUT = 0b0000010000
| DONOTRETRY = 0b1000000000
and during some data initialization, I have a uint16 value I want to convert to the enum's type, StatusWord, so I can compare it's properties:
let value: uint16 = 0b1000001001us
let flags: StatusWord = StatusWord value
but, as you might be able to guess, this code doesn't compile; the conversion isn't available. Likewise, I also can't do explicit casts, eg. value :> StatusWord or value :?> StatusWord. This is a simple task in C#, so I'm having trouble figuring out why I can't do it in F#.
So, two things you have to worry about. One (which I think you already realize) is that your underlying enum type is int32, and your value is uint16, so a conversion will need to happen somewhere. Two, you have to construct the enum type.
StatusWord looks like a constructor (similar to a union case member), but it's not. So here are two ways to do it with your uint16 value, and a third way to do it which is much better for readability, if you can do it that way.
let value = 0b1000001001us
// use F# enum operator
let flags1 = enum<StatusWord> (int value)
// use static Enum class
let flags2 = Enum.Parse(typeof<StatusWord>, string value) :?> StatusWord
// do bitwise stuff, of course now the compiler knows what you're doing
let flags3 = StatusWord.DATAPROCESS ||| StatusWord.PACKETSIZEERROR ||| StatusWord.DONOTRETRY
Because there are multiple ways, I had to refresh my memory, which I did at
https://fsharpforfunandprofit.com/posts/enum-types/
which is highly recommended reading (that article and the rest of that blog - it's how many people learn F#).
To convert a numerical value to an enum in F#, you can use the built-in LanguagePrimitives.EnumOfValue function.
let flags: StatusWord = LanguagePrimitives.EnumOfValue value
In your example, this does not actually work, because the type of value is uint16, but the underlying type of the enum is int (because the values do not have the us suffix). To get that to work, you'll need to either convert uint32 to int, or change the definition of your enum. The following works perfectly:
[<Flags>]
type StatusWord =
| DATAPROCESS = 0b0000000001us
| ERRORPRESENT = 0b0000000010us
| CHECKSUMERROR = 0b0000000100us
| PACKETSIZEERROR = 0b0000001000us
| TIMEOUT = 0b0000010000us
| DONOTRETRY = 0b1000000000us
let value: uint16 = 0b1000001001us
let flags: StatusWord = LanguagePrimitives.EnumOfValue value
EDIT: Jim's answer mentions the enum function. For some reason (I'm not sure why!) this only works with int32 arguments, so using EnumOfValue is probably better if you want to keep the base type of your enum as uint16. If you wanted to keep that as int32, then enum is much nicer option!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With