这与How to enumerate an enum/type in F#中的问题非常相关。我定义了一个联合类型,然后我需要在静态方法中使用该类型的所有可能情况。例如:
type Interests =
| Music
| Books
| Movies
with
static member GetValue( this) = match this with
| Music -> 0
| Books -> 5
| Movies -> 0
static member GetSeqValues() = allCases|>Seq.map(GetValue)
我如何获得allCases?
非常感谢
答案 0 :(得分:12)
您可以使用FSharpType.GetUnionCases()
中的Microsoft.FSharp.Reflection
来获取所有受歧视联盟的案例。在您的示例中,它看起来像这样:
type Interests =
| Music
| Books
| Movies
static member GetValue(this) = (...)
static member GetSeqValues() =
// Get all cases of the union
let cases = FSharpType.GetUnionCases(typeof<Interests>)
[ for c in cases do
// Create value for each case (assuming it has no arguments)
let interest = FSharpValue.MakeUnion(c, [| |]) :?> Interests
yield GetValue(interest) ]
然而,问题是您可能无法创建要传递给GetValue
成员的实例,因为某些情况可能有参数(在调用MakeUnion
时您必须传递一个数组参数和我只用了一个空数组。例如,如果你有:
type Sample =
| A of int
| B of bool
答案 1 :(得分:0)
我让an expansion of Tomas' work处理任何类型的FSharp Union(处理union case的属性) 只要你提供了如何处理非工会子女的逻辑。
let rec getAllDUCases fNonUnionArg t : obj list =
let getAllDUCases = getAllDUCases fNonUnionArg
// taken from http://stackoverflow.com/questions/6497058/lazy-cartesian-product-of-multiple-sequences-sequence-of-sequences
let cartesian_product2 sequences =
let step acc sequence = seq {
for x in acc do
for y in sequence do
yield seq { yield! x; yield y}}
Seq.fold step (Seq.singleton Seq.empty) sequences
let makeCaseTypes (fUnion:Type-> obj list) (fNonUnionArg:Type -> obj) (uc: UnionCaseInfo) : UnionCaseInfo*(obj list list) =
let constructorArgs =
uc.GetFields()
|> Seq.map (fun f ->
if FSharpType.IsUnion f.PropertyType then
let childTypes = fUnion f.PropertyType
if
childTypes
|> Seq.exists (fun ct -> FSharpType.IsUnion (ct.GetType()) |> not) then
failwithf "fUnion returned a bad type in list %A" childTypes
childTypes
else [ fNonUnionArg f.PropertyType] )
|> List.ofSeq
let allCombinationsOfFieldPossibles =
cartesian_product2 constructorArgs
|> Seq.map List.ofSeq
|> List.ofSeq
uc, allCombinationsOfFieldPossibles
// with help from http://stackoverflow.com/a/4470670/57883
let result =
FSharpType.GetUnionCases t
|> Seq.map (makeCaseTypes getAllDUCases fNonUnionArg)
|> List.ofSeq
let result =
result
|> Seq.map (fun (uc,allFieldComboCases) -> allFieldComboCases |> Seq.map (fun args-> FSharpValue.MakeUnion(uc,args |> Array.ofList)))
|> Seq.collect id
|> Seq.map box
|> List.ofSeq
result