【问题标题】:How to enumerate an enum/type in F#如何在 F# 中枚举枚举/类型
【发布时间】:2010-02-02 04:48:09
【问题描述】:

我有一个这样定义的枚举类型:

type tags = 
    | ART  = 0
    | N    = 1
    | V    = 2 
    | P    = 3
    | NULL = 4

有没有办法做一个for ... in tags do

这是我得到的错误:

值、构造函数、命名空间或 类型 tags 未定义

【问题讨论】:

标签: .net f# enums


【解决方案1】:

怎么样:

let enumToList<'a> = (Enum.GetValues(typeof<'a>) :?> ('a [])) |> Array.toList

这具有提供强类型列表的优点

使用只是做:

let tagList = enumToList<tags>

【讨论】:

  • 这通常是我发现自己需要的,而不是普通的int 值。
【解决方案2】:

使用Enum.GetValues:

let allTags = Enum.GetValues(typeof<tags>)

【讨论】:

  • 应该是 Enum.GetValues(typeof)。我之前尝试过,但不知道 typeof 的不同语法。谢谢!
  • 您第一次提供的代码没有与 Jared 发布的代码不符。如果另一位读者碰巧碰到这个问题,他会认为 Enum.GetValues 可以与联合一起使用,但事实并非如此。现在你解释了我恢复了我的 -1
  • 请注意,.NetCF 或 silverlight 运行时中不存在 Enum.GetValues。
  • 我的问题是 GetValues 将返回一个数组,我无法将它转换回枚举。我试过enum&lt;tags&gt; tag,但没用。
  • @Jared,请参阅我处理 GetValues 返回的数组的答案
【解决方案3】:

这是一个完整的示例,它打印有关任何受歧视联合的信息。它显示了如何获取受歧视联合的案例以及如何获取字段(如果您需要它们)。该函数打印给定可区分联合的类型声明:

open System
open Microsoft.FSharp.Reflection

let printUnionInfo (typ:Type) = 
  printfn "type %s =" typ.Name
  // For all discriminated union cases
  for case in FSharpType.GetUnionCases(typ) do
    printf "  | %s" case.Name
    let flds = case.GetFields()
    // If there are any fields, print field infos
    if flds.Length > 0 then 
      // Concatenate names of types of the fields
      let args = String.concat " * " [ for fld in flds -> fld.PropertyType.Name ] 
      printf " of %s" args
    printfn ""    

// Example
printUnionInfo(typeof<option<int>>)

【讨论】:

  • 帖子中的原始类型声明(在您编辑之前)是一个有区别的联合...当然枚举在 F# 中也很有用,但仅在少数情况下。
  • 我对帖子所做的唯一修改是修复了从“枚举”到“枚举”的错字。我认为基于 OP 始终打算将问题与枚举有关的主题,但在未正确将 tags 定义为枚举时引入了混淆。
  • 最初的问题是显示有区别的联合——不是枚举。 @Chris Smith 在事后将“= ”添加到原始问题中,并完全改变了原始发布者询问的类型。我不确定这是一个如此明智的编辑,因为它完全改变了问题的性质。
  • @Onorio Catenacci:我同意。对于OP的含义,肯定有很多困惑。他在主题中声明了“枚举”,但在他的帖子中定义了一个有区别的联合。
  • @Tomas Petricek:没问题 Tomas;这里有很多混乱!顺便说一句,我喜欢你的书 Real-World Functional Programming。
【解决方案4】:

要使其成为枚举,您需要为每种情况显式赋予值,否则它是联合类型:

type tags = 
    | ART = 0
    | N = 1
    | V = 2
    | P = 3
    | NULL= 4
let allTags = System.Enum.GetValues(typeof<tags>)

【讨论】:

    【解决方案5】:

    罗伯特关于如何生成一个实际的枚举并获取它的案例是正确的。如果你有真正的联合类型,你可以通过Microsoft.FSharp.Reflection.FSharpType.GetUnionCases 函数获取案例。

    【讨论】:

      【解决方案6】:

      您可以使用Enum.GetValues,它返回对象的Array,然后您必须向下转换为整数值。 (注意:我使用的是 Mono 的 F# 实现;也许 .NET 的情况有所不同。)

      以下是我编写的一些函数,用于获取所有枚举值的列表并获取最小值和最大值:

      open System
      
      module EnumUtil =
      
          /// Return all values for an enumeration type
          let EnumValues (enumType : Type) : int list =
              let values = Enum.GetValues enumType
              let lb = values.GetLowerBound 0
              let ub = values.GetUpperBound 0
              [lb .. ub] |> List.map (fun i -> values.GetValue i :?> int) 
      
          /// Return minimum and maximum values for an enumeration type
          let EnumValueRange (enumType : Type) : int * int =
              let values = EnumValues enumType
              (List.min values), (List.max values)
      

      【讨论】:

        【解决方案7】:

        在 .Net 5 中有一个通用的 Enum.GetValues 重载,它消除了强制转换的需要。

        Enum.GetValues<T>()
        

        【讨论】:

          【解决方案8】:
          type Options = 
              | Exit          = 0
              | CreateAccount = 1
          
          Console.WriteLine()
          Console.WriteLine("Choose an option:")
          let allOptions = Enum.GetValues(typeof<Options>)
          for option in allOptions do
              if (option <> null) then
                  Console.WriteLine(sprintf "%d: %s" (option :?> int) (option.ToString()))
          let optionChosen = System.Console.ReadLine()
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2012-09-16
            • 1970-01-01
            • 2014-07-23
            • 2017-01-14
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多