我有一个有区别的联合,我想根据一个字符串(从JSON文件中读取)选择一个案例。这很容易做到:
type MyDU = A | B
let str = "B"
let myDU : MyDU =
match str with
| "A" -> MyDU.A
| "B" -> MyDU.B
| _ -> failwith "whatever"
// val myDU : MyDU = B
但是,有时会出现很多情况,需要大量打字。
Microsoft.FSharp.Reflection
库允许我获得UnionCaseInfo
对象:
open Microsoft.FSharp.Reflection
let myDUInfo : UnionCaseInfo =
FSharpType.GetUnionCases(typeof<MyDU>)
|> Array.find (fun x -> x.Name = str)
// val myDUInfo : UnionCaseInfo = MyDU.B
我想将myDUInfo
转换为联合案例,以便获得与依赖match
的上述代码相同的结果,但无需键入与所有案例相对应的字符串。< / p>
这可能吗?
答案 0 :(得分:3)
要实例化联合案例,请使用FSharpValue.MakeUnion
method。这是一个函数,它将根据名称实例化一个联合案例:
let instantiate<'t> name =
Reflection.FSharpType.GetUnionCases( typeof<'t> )
|> Seq.tryFind (fun uc -> uc.Name = name)
|> Option.map (fun uc -> Reflection.FSharpValue.MakeUnion( uc, [||] ) :?> 't)
用法:
> type T = A | B | C
> instantiate<T> "A"
val it : T option = Some A
注意:此函数假定但不确定union情况没有参数。如果你给一个带参数的案例,它就会崩溃:
> type T = A of int | B | C
> instantiate<T> "A"
System.Reflection.TargetParameterCountException: Parameter count mismatch.
at System.Reflection.RuntimeMethodInfo.InvokeArgumentsCheck(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
at FSI_0002.instantiate@5.Invoke(UnionCaseInfo uc) in c:\o\a.fsx:line 5
at Microsoft.FSharp.Core.OptionModule.Map[T,TResult](FSharpFunc`2 mapping, FSharpOption`1 option)
at <StartupCode$FSI_0006>.$FSI_0006.main@()
Stopped due to error
我将此问题的解决方案作为读者的练习(提示:使用UnionCase.GetFields
method)。