我正在尝试从字符串创建DU个案。我能看到这样做的唯一方法是通过Microsoft.FSharp.Reflection.FSharpType.GetUnionCases
枚举DU案例,然后选择匹配字符串的UnionCase
(使用.Name
),然后制作实际的DU案例除此之外使用FSharpValue.MakeUnion
。
这样做是不是更简单/更优雅?在我的场景中,我有一个DU,有几百个关键字案例。我必须从文件中读取字符串(关键字)并从中提取类型。通过将案例放入Map中我做了一些“优化”,但我希望有更好的方法来做到这一点。
我有以下内容,例如:
type Keyword =
| FOO
| BAR
| BAZ
| BLAH
let mkKeywords (file: string) =
use sr = new StreamReader(file)
let caseMap =
FSharpType.GetUnionCases(typeof<Keyword>)
|> Array.map (fun c -> (c.Name, FSharpValue.MakeUnion(c, [||]) :?> Keyword))
|> Map.ofArray
[
while not sr.EndOfStream do
let l = sr.ReadLine().Trim()
match caseMap.TryFind l with
| Some c -> yield c
| None -> failwith <| "Could not find keyword: " + l
]
答案 0 :(得分:13)
我找到了this便捷的代码段...
open Microsoft.FSharp.Reflection
let toString (x:'a) =
match FSharpValue.GetUnionFields(x, typeof<'a>) with
| case, _ -> case.Name
let fromString<'a> (s:string) =
match FSharpType.GetUnionCases typeof<'a> |> Array.filter (fun case -> case.Name = s) with
|[|case|] -> Some(FSharpValue.MakeUnion(case,[||]) :?> 'a)
|_ -> None
...这样可以轻松地将两行代码添加到任何DU ...
type A = X|Y|Z with
override this.ToString() = FSharpUtils.toString this
static member fromString s = FSharpUtils.fromString<A> s
答案 1 :(得分:8)
我会像这样使用模式匹配:
type Keyword =
| FOO
| BAR
| BAZ
| BLAH
let matchKeyword (word:string) : Keyword option =
match word with
| "FOO" -> Some FOO
| "BAR" -> Some BAR
| "BAZ" -> Some BAZ
| "BLAH" -> Some BLAH
| _ -> None
也许在我的编辑器中第一次使用正则表达式自动生成匹配语句,但这只是因为你有数百个案例。但我不确定它是否比你更好的解决方案。
答案 2 :(得分:8)
由于案件没有价值,另一种选择是使用enums:
type Keyword =
| FOO = 0
| BAR = 1
| BAZ = 2
| BLAH = 3
let strings = ["FOO";"BAR"]
let keywords =
[for s in strings -> s, Keyword.Parse(typeof<Keyword>, s)]
|> Map.ofList
然后您只需使用Enum.Parse。