使用 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 :> StatusWordvalue :?> 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 是更好的选择!