How to enumerate an enum/type in F#告诉我们如何在F#中获取.Net枚举类型的枚举器:
使用:Enum.GetValues(typeof<MyType>)
然而,当我使用它时,我发现了一个限制。我可以解决这个限制,但我正在寻找更好的方法。
问题是该解决方案返回一个.Net数组对象,但要使用它我们需要强制转换它,并且这种转换对于迭代来说是不实用的。
type Colors =
| Red = 0
| Blue = 1
| Green = 2
// Strongly typed function, to show the 'obj' in real use
let isFavorite color = color = Colors.Green
// Iterate over the Enum (Colors)
for color in Enum.GetValues(typeof<Colors>) do
printfn "Color %A. Is Favorite -> %b" color (isFavorite color) // <-- Need to cast
(IsFavorite color)
引发Colors
(预期)与obj
(实际)之间的类型冲突
这很容易解决:
for obj in Enum.GetValues(typeof<Colors>) do
printfn "Color %A. Is Favorite -> %b" obj (isFavorite (unbox<Colors> obj))
但是,如果在几个地方需要(unbox<Colors> obj)
怎么办?
本地let color = ...
就足够了,但理想情况下,我们会使用一个返回seq<Colors>
的枚举表达式。
我已经能够构建该表达式,但它是:a。难以建立,和b。啰嗦。
let colorsSeq =
Seq.cast (Enum.GetValues(typeof<Colors>))
|> Seq.map (fun o -> unbox<Colors> o)
for color in colorsSeq do
printfn "Color %A. Is Favorite -> %b" color (isFavorite color)
有更好的表达吗?
答案 0 :(得分:5)
Enum.GetValues
是一个旧的BCL API,所以你无能为力......我不认为你能以显着更简洁的方式得到你想要的东西比你已经拥有的,但你可以减少它:
let colorsSeq = Enum.GetValues(typeof<Colors>) |> Seq.cast<Colors>
如果您需要做很多这样的事情,可以考虑将其打包成通用函数:
module Enum =
let values<'a> = Enum.GetValues(typeof<'a>) |> Seq.cast<'a>
这将使您能够像这样使用它:
for color in Enum.values<Colors> do
printfn "Color %A. Is Favorite -> %b" color (isFavorite color)
答案 1 :(得分:3)
这似乎是关于最简单的版本:
let t : Colors seq = unbox (Enum.GetValues(typeof<Colors>))
答案 2 :(得分:1)
最简单的通用表达式是对基础类型'T[]
的转换(或取消装箱)。因此
module Enum =
open System
let cases<'T when 'T :> Enum> = Enum.GetValues typeof<'T> :?> 'T[]
转换为C#为
public static class Enum
{
public static T[] cases<T>() where T : Enum
{
return (T[])Enum.GetValues(typeof(T));
}
}
插入问题中的代码,它给出了这个输出:
type Colors =
| Red = 0
| Blue = 1
| Green = 2
let isFavorite color = color = Colors.Green
for color in Enum.cases<Colors> do
printfn "Color %A. Is Favorite -> %b" color (isFavorite color)
//Color Red. Is Favorite -> false
//Color Blue. Is Favorite -> false
//Color Green. Is Favorite -> true