是否有像Java的enum.ordinal()这样的.NET构造?

时间:2019-02-08 14:43:06

标签: .net enums f#

如果我在F#中具有以下枚举:

type Note =
    | C = 0
    | D = 2
    | E = 4
    | F = 5
    | G = 7
    | A = 9
    | B = 11

但是在某些时候,我需要其中的项目的序数,例如Note.C = 1, Note.D = 2,等。显然,在其他语言中,foo.ordinal()也可以工作,但是在这里必须使用这样的功能:

let getNoteOrdinal = function
    |Note.C -> 1
    |Note.D -> 2
    |Note.E -> 3
    |Note.F -> 4
    //etc

该功能是否必要或有更好的选择?

2 个答案:

答案 0 :(得分:4)

.NET中的枚举只是整数类型之上的一层,在这种情况下,您的值是int

对于每个the docs,您可以进行简单的转换来获取该值,例如:

let value = int Note.B

在这种情况下,value将为11

要找到序数,您可以利用一个内置函数,该函数为您按顺序提供所有值的数组,然后找到您要查找的值的索引。例如:

let getNoteOrdinal (note: Note) =
    let values = Enum.GetValues(typeof<Note>)
    Array.IndexOf(values, note) + 1

let value = getNoteOrdinal Note.E

在这种情况下,value将为3

您可以按照@ReedCopsey的建议更进一步,并创建一个通用函数,该函数将为您提供 any 枚举值的序数:

let getEnumOrdinal (e: 'a when 'a : enum<'b> and 'a : equality) =    
    let values = Enum.GetValues(e.GetType())
    Array.IndexOf(values, e) + 1

答案 1 :(得分:1)

我建议不要在F#中完全使用枚举,除非与另一种.NET语言互操作需要此枚举。您可以使用已区分的联合并将注释值存储在数组中(这是模块级别的值,在应用程序启动时将对其进行一次评估)。然后,您可以编写使用数组的函数。

type Note = C | D | E | F | G | A | B

let noteValues =
    [| C, 0
       D, 2
       E, 4
       F, 5
       G, 7
       A, 9
       B, 11 |]

let getNoteValue note =
    noteValues |> Array.find (fun (n, _) -> note = n) |> snd

let getNoteOrdinal note =
    noteValues |> Array.findIndex (fun (n, _) -> n = note) |> (+) 1

用法示例:

getNoteValue C // 0
getNoteValue D // 2

getNoteOrdinal C // 1
getNoteOrdinal D // 2