使用 Flags 属性将整数转换为枚举类型
Cast integer to enum type with Flags attribute
我有一个带有 flags 属性的枚举类型:
[<Flags>]
type StatusWord =
| DATAPROCESS = 0b0000000001
| ERRORPRESENT = 0b0000000010
| CHECKSUMERROR = 0b0000000100
| PACKETSIZEERROR = 0b0000001000
| TIMEOUT = 0b0000010000
| DONOTRETRY = 0b1000000000
在一些数据初始化期间,我有一个 uint16
值,我想将其转换为枚举类型 StatusWord
,因此我可以比较它的属性:
let value: uint16 = 0b1000001001us
let flags: StatusWord = StatusWord value
但是,正如您可能猜到的那样,这段代码无法编译;转换不可用。同样,我也不能进行显式转换,例如。 value :> StatusWord
或 value :?> StatusWord
。这是 C# 中的一个简单任务,所以我无法弄清楚为什么我不能在 F# 中完成它。
因此,您需要担心两件事。一个(我想您已经意识到)是您的基础枚举类型是 int32,而您的值是 uint16,因此需要在某处进行转换。二,你必须构造枚举类型。
StatusWord 看起来像构造函数(类似于 union case 成员),但事实并非如此。所以这里有两种方法可以用你的 uint16 值来做,还有第三种方法,如果你能那样做的话,它的可读性要好得多。
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
因为有多种方法,所以我不得不刷新记忆,我在
https://fsharpforfunandprofit.com/posts/enum-types/
强烈推荐阅读(那篇文章和该博客的其余部分 - 有多少人学习 F#)。
要在 F# 中将数值转换为枚举,可以使用内置的 LanguagePrimitives.EnumOfValue
函数。
let flags: StatusWord = LanguagePrimitives.EnumOfValue value
在您的示例中,这实际上不起作用,因为 value
的类型是 uint16
,但枚举的基础类型是 int
(因为值不有 us
后缀)。要让它工作,您需要将 uint32
转换为 int
,或者更改枚举的定义。以下完美运行:
[<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
编辑: Jim 的回答提到了 enum
函数。出于某种原因(我不确定为什么!)这仅适用于 int32
参数,因此如果您想将枚举的基类型保留为 uint16
,则使用 EnumOfValue
可能更好.如果您想将其保留为 int32
,那么 enum
是更好的选择!
我有一个带有 flags 属性的枚举类型:
[<Flags>]
type StatusWord =
| DATAPROCESS = 0b0000000001
| ERRORPRESENT = 0b0000000010
| CHECKSUMERROR = 0b0000000100
| PACKETSIZEERROR = 0b0000001000
| TIMEOUT = 0b0000010000
| DONOTRETRY = 0b1000000000
在一些数据初始化期间,我有一个 uint16
值,我想将其转换为枚举类型 StatusWord
,因此我可以比较它的属性:
let value: uint16 = 0b1000001001us
let flags: StatusWord = StatusWord value
但是,正如您可能猜到的那样,这段代码无法编译;转换不可用。同样,我也不能进行显式转换,例如。 value :> StatusWord
或 value :?> StatusWord
。这是 C# 中的一个简单任务,所以我无法弄清楚为什么我不能在 F# 中完成它。
因此,您需要担心两件事。一个(我想您已经意识到)是您的基础枚举类型是 int32,而您的值是 uint16,因此需要在某处进行转换。二,你必须构造枚举类型。
StatusWord 看起来像构造函数(类似于 union case 成员),但事实并非如此。所以这里有两种方法可以用你的 uint16 值来做,还有第三种方法,如果你能那样做的话,它的可读性要好得多。
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
因为有多种方法,所以我不得不刷新记忆,我在
https://fsharpforfunandprofit.com/posts/enum-types/
强烈推荐阅读(那篇文章和该博客的其余部分 - 有多少人学习 F#)。
要在 F# 中将数值转换为枚举,可以使用内置的 LanguagePrimitives.EnumOfValue
函数。
let flags: StatusWord = LanguagePrimitives.EnumOfValue value
在您的示例中,这实际上不起作用,因为 value
的类型是 uint16
,但枚举的基础类型是 int
(因为值不有 us
后缀)。要让它工作,您需要将 uint32
转换为 int
,或者更改枚举的定义。以下完美运行:
[<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
编辑: Jim 的回答提到了 enum
函数。出于某种原因(我不确定为什么!)这仅适用于 int32
参数,因此如果您想将枚举的基类型保留为 uint16
,则使用 EnumOfValue
可能更好.如果您想将其保留为 int32
,那么 enum
是更好的选择!