通过解析json,我得到了JObject类型的结果:
let j = JObject.Parse x
我要做的代码是这样的:
if j = null then
... do stuff
else if j["aa"] <> null then
... do stuff
else if j["bb"] <> null then
... do stuff
else if j["cc"] <> null and j["dd"] <> null then
... do stuff
有没有一种干净的方法来进行比赛?
做类似
的语句| _ when j.["error"] <> null ->
看起来不是很干净。可以做得更好吗?
答案 0 :(得分:2)
let j = JObject.Parse x
let doSomething s = printf "%A" s
if isNull j then
()
else
[ j.["aa"]; j.["bb"]; j.["cc"] ]
|> List.tryFind (fun s -> s |> Option.ofObj |> Option.isSome)
|> doSomething
let j = JObject.Parse x
let doSomething s = printf "%A" s
if isNull j then
()
else
[ j.["aa"]; j.["bb"]; j.["cc"] ]
|> List.choose (fun s -> s |> Option.ofObj)
|> List.iter doSomething
let j = JObject.Parse x
let doSomethingA s = printf "%A" s
let doSomethingB s = printf "%A" s
let doSomethingC s = printf "%A" s
if isNull j then
()
else
[
j.["aa"], doSomethingA
j.["bb"], doSomethingB
j.["cc"], doSomethingC
]
|> List.tryFind (fun (s, _) -> s |> Option.ofObj |> Option.isSome)
|> Option.iter (fun (s, f) -> f s)
答案 1 :(得分:2)
如果您创建一个活动模式,该模式返回匹配的JToken
...
let (|NonNull|_|) prop (o : JObject) =
o.[prop] |> Option.ofObj
您可以这样写:
let handleAA (a : JToken) = ()
match JObject.Parse "{}" with
| null -> () // ...
| NonNull "aa" a -> handleAA a
| NonNull "bb" b & NonNull "cc" c -> ()
| _ -> () // all other
更新
如果您需要更多的功能,活动模式非常丰富...
let (|J|_|) prop (o : obj) =
match o with
| :? JObject as o -> o.[prop] |> Option.ofObj
| _ -> None
let (|Deep|_|) (path : string) (o : obj) =
let get t p = t |> Option.bind (fun t -> (``|J|_|``) p t)
match o with
| :? JToken as t ->
path.Split('.') |> Array.fold get (Option.ofObj t)
| _ -> None
...一些帮手...
let jV (t : JToken) = t.Value<string>()
let handle t = jV t |> printfn "single: %s"
let handle2 a b = printfn "(%s, %s)" (jV a) (jV b)
...解析函数...
let parse o =
match JsonConvert.DeserializeObject o with
| null -> printfn "null"
| J "aa" a -> handle a
| J "bb" b & J "cc" c -> handle2 b c
| J "bb" b & J "dd" _ -> handle b
| Deep "foo.bar" bar & Deep "hello.world" world -> handle2 bar world
| Deep "foo.bar" bar -> handle bar
| o -> printfn "val: %A" o
...然后走开:
parse "null" // null
parse "42" // val: 42L
parse "{ aa: 3.141 }" // single: 3.141
parse "{ bb: 2.718, cc: \"e\" }" // (2.718, e)
parse "{ bb: 2.718, dd: 0 }" // single: 2.718
parse "{ foo: { bar: \"baz\" } }" // single: baz
parse "{ foo: { bar: \"baz\" }, hello: { world: \"F#|>I❤\" } }" // (baz, F#|>I❤)
答案 2 :(得分:1)
您可以创建一个活动模式以匹配非空值...
let (|NonNull|_|) = function null -> None | v -> Some v
...这将允许以下操作。
if isNull j then
//do stuff
else
match j.["aa"], j.["bb"], j.["cc"], j.["dd"] with
| NonNull aa, _, _, _ -> //do stuff
| _, NonNull bb, _, _ -> //do stuff
| _, _, NonNull cc, NonNull dd -> //do stuff
答案 3 :(得分:1)
您可以为每个键列出一个动作列表,以便可以对每个键统一应用null检查逻辑。
let j = JObject.Parse x
let doStuff key value = printfn "%s=>%s" key value
如果您想对每个键都应用doStuff,则可以进行迭代。这是您的示例,但没有其他示例,因此它会针对每个存在的键进行操作。
["aa", doStuff
"bb", doStuff
"cc", doStuff]
|> List.iter (fun (key,action) ->
j.TryGetValue key
|> snd
|> Option.ofObj
|> Option.iter (action key))
与您的示例更紧密地匹配,在您仅对第一个出现的键执行doStuff的情况下,可以使用select来仅获取有效的值,操作。
["aa", doStuff
"bb", doStuff
"cc", doStuff]
|> Seq.choose (fun (key,action) ->
j.TryGetValue key
|> snd
|> Option.ofObj
|> Option.map (fun v -> action key v))
|> Seq.tryHead
如果存在匹配的键并且doStuff返回值,则此版本还返回所应用doStuff的结果。这只是在滥用Seq的惰性,使其仅调用第一个值,但您也可以将函数映射到调用Seq.tryHead的结果。