如何从字符串中获得有区别的联合用例? [英] How do I get a discriminated union case from a string?
问题描述
我有一个已区分的联合,我想根据一个字符串(从JSON文件读取)选择一个案例.这很容易做到:
I have a discriminated union and I want to select a case based on a string (which is read from a JSON file). This is easy to do:
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
但是,有时情况很多,这需要大量输入.
However, sometimes there are many cases, which would require a lot of typing.
Microsoft.FSharp.Reflection
库允许我获取UnionCaseInfo
对象:
The Microsoft.FSharp.Reflection
library allows me to get a UnionCaseInfo
object:
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
的代码相同的结果,但不必键入与所有大小写相对应的字符串.
I would like to convert myDUInfo
into a union case so as to get the same result as the code above relying on match
, but without having to type the strings corresponding to all the cases.
这可能吗?
推荐答案
To instantiate a union case, use the FSharpValue.MakeUnion
method. Here is a function that will instantiate a union case given its name:
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
注意:此函数假定但不保证并集大小写没有参数.如果给它提供一个带有参数的案例,它将崩溃:
NOTE: this function assumes, but does not make sure, that the union case has no arguments. If you give it a case with arguments, it will crash:
> 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
方法).
I leave resolution of this problem as an exercise for the reader (hint: use the UnionCase.GetFields
method).
这篇关于如何从字符串中获得有区别的联合用例?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!