使用反射而不是枚举的F#判别联合枚举
我使用反射(例如)枚举F#中一些有区别的并集中的值。我想使用从使用反射生成不同记录类型中获得的值,这些记录类型是由我正在枚举的有区别的联合组成的,但我不确定如何将类型UnionCaseInfo转换为实际的联合案例。有可能演这样的演员吗?下面的代码正好代表了我要做的事情(区分的并集中的值不同,变量名也不同)。我知道我可以使用枚举法,但我宁愿不使用枚举法,也不使用歧视工会法使用反射而不是枚举的F#判别联合枚举,f#,f#-3.0,F#,F# 3.0,我使用反射(例如)枚举F#中一些有区别的并集中的值。我想使用从使用反射生成不同记录类型中获得的值,这些记录类型是由我正在枚举的有区别的联合组成的,但我不确定如何将类型UnionCaseInfo转换为实际的联合案例。有可能演这样的演员吗?下面的代码正好代表了我要做的事情(区分的并集中的值不同,变量名也不同)。我知道我可以使用枚举法,但我宁愿不使用枚举法,也不使用歧视工会法 open System open Microsoft.FSharp.Collections open Microsoft.FS
open System
open Microsoft.FSharp.Collections
open Microsoft.FSharp.Reflection
let GetUnionCaseName (x:'a) =
match FSharpValue.GetUnionFields(x, typeof<'a>) with
| case, _ -> case.Name
type shape =
| Square
| Circle
| Triangle
| Other
type color =
| Black
| Red
| Blue
| Green
| White
type coloredShape = { Shape: shape; Color: color }
let shapeCases = FSharpType.GetUnionCases typeof<shape>
let colorCases = FSharpType.GetUnionCases typeof<color>
let boardOfRelevantPossibilities = Microsoft.FSharp.Collections.Array2D.init<coloredShape> 5 3 (fun x y -> {Shape = Other; Color = Black})
let OtherShape = GetUnionCaseName(shape.Other)
let rand = Random()
for shapeCase in shapeCases do
// Is there a way to do the following comparison this without using string comparisons
if not (shapeCase.Name.Equals OtherShape) then
for colorCase in colorCases do
let mutable addedToBoard = false
while not addedToBoard do
let boardRowIndex = rand.Next(0,4)
let boardColumnIndex = rand.Next(0,2)
if boardOfRelevantPossibilities.[boardRowIndex,boardColumnIndex].Shape.Equals shape.Other then
addedToBoard <- true
// I want to utilize colorCase instead of other and shapeCase instead of black
boardOfRelevantPossibilities.[boardRowIndex,boardColumnIndex] <- {Shape = Other; // Shape should be determined by shapeCase instead of Other
Color = White } // Color should be determined by colorCase instead of White
Console.ReadKey() |> ignore
开放系统
打开Microsoft.FSharp.Collections
打开Microsoft.FSharp.Reflection
让GetUnionCaseName(x:'a)=
匹配FSharpValue.GetUnionFields(x,typeof()=
GetUnionCases(typeof{Shape=Other;Color=Black})
设rand=Random()
对于AllunionCase()中的shapeCase
//不再进行字符串比较
如果是形状,那么是另一个
对于allUnionCases()中的colorCase
设可变addedToBoard=false
虽然没有添加,但请执行以下操作
让boardRowIndex=rand.Next(0,numberOfRows)
让boardColumnIndex=rand.Next(0,numberOfColumns)
如果BoardOfRelatedProbabilities.[boardRowIndex,boardColumnIndex].Shape.Equals Shape.Other then
addedToBoard老实说,我更喜欢在静态方法中手动枚举所有联合案例,而不是通过反射创建它们
正如@John所说,您还需要使用以下步骤:
字符串比较到底有什么问题?它应该工作得很好?我宁愿直接与形状进行比较。另外,事后看来,这真的没关系。我猜如果你知道没有参数,你可以使用FSharpValue。MakeUnion
可以做你想做的事情,只需将它转换为形状:{Shape=FSharpValue.MakeUnion(shapeCase,[| |]]:?>Shape;Color=White}
以这种方式强制转换的问题是以下代码(当插入我发布的原始代码(这是最上面的代码片段)时):BoardOfRelationProbabilities.[boardRowIndex,boardColumnIndex]Shape;Color=FSharpValue.MakeUnion(shapeCase,[|]):?>color}
实际生成并将在运行代码时生成以下运行时错误:System.InvalidCastException
。
open System
open Microsoft.FSharp.Collections
open Microsoft.FSharp.Reflection
let allUnionCases<'T>() =
FSharpType.GetUnionCases(typeof<'T>)
|> Array.map (fun case -> FSharpValue.MakeUnion(case, [||]) :?> 'T)
type shape =
| Square
| Circle
| Triangle
| Other
type color =
| Black
| Red
| Blue
| Green
| White
type coloredShape = { Shape: shape; Color: color }
let shapeCases = FSharpType.GetUnionCases typeof<shape>
let colorCases = FSharpType.GetUnionCases typeof<color>
let numberOfRows = 5
let numberOfColumns = 3
let boardOfRelevantPossibilities = Microsoft.FSharp.Collections.Array2D.init<coloredShape> numberOfRows numberOfColumns (fun x y -> {Shape = Other; Color = Black})
let rand = Random()
for shapeCase in allUnionCases<shape>() do
// No string comparison anymore
if shapeCase <> shape.Other then
for colorCase in allUnionCases<color>() do
let mutable addedToBoard = false
while not addedToBoard do
let boardRowIndex = rand.Next(0,numberOfRows)
let boardColumnIndex = rand.Next(0,numberOfColumns)
if boardOfRelevantPossibilities.[boardRowIndex,boardColumnIndex].Shape.Equals shape.Other then
addedToBoard <- true
// utilizing colorCase and shapeCase to create records to fill array
boardOfRelevantPossibilities.[boardRowIndex,boardColumnIndex] <- {Shape = shapeCase; Color = colorCase }
printfn "%A" boardOfRelevantPossibilities
Console.ReadKey() |> ignore
let allUnionCases<'T>() =
FSharpType.GetUnionCases(typeof<'T>)
|> Array.map (fun case -> FSharpValue.MakeUnion(case, [||]) :?> 'T)
/// Use type params for clarity; type inference should work fine without them
for shapeCase in allUnionCases<shape>() do
for colorCase in allUnionCases<color>() do
let mutable addedToBoard = false
while not addedToBoard do
let r = rand.Next(0,4)
let c = rand.Next(0,2)
if boardOfRelevantPossibilities.[r, c].Shape = Other then
addedToBoard <- true
boardOfRelevantPossibilities.[r, c] <- { Shape = shapeCase;
Color = colorCase }