Serialization 无法序列化F#Chiron中的歧视联合
如果我有:Serialization 无法序列化F#Chiron中的歧视联合,serialization,f#,discriminated-union,Serialization,F#,Discriminated Union,如果我有: type a = B | C 如何将静态成员写入JSON和FromJson 我知道如何为记录类型编写它(如中的示例所示),但我找不到DU的任何示例 编辑 在s952163给出了有用的答案(以及后续的评论)之后,我对代码进行了调整,以尝试使用选择a | B的“简单”DU(而不是字符串B的…)。我的代码是: type SimpleDU = | A | B static member ToJson (t : SimpleDU) = match t
type a = B | C
如何将静态成员写入JSON和FromJson
我知道如何为记录类型编写它(如中的示例所示),但我找不到DU的任何示例
编辑 在s952163给出了有用的答案(以及后续的评论)之后,我对代码进行了调整,以尝试使用选择a | B的“简单”DU(而不是字符串B的…)。我的代码是:
type SimpleDU =
| A
| B
static member ToJson (t : SimpleDU) =
match t with
| A -> Json.writeNone "a"
| B -> Json.writeNone "b"
static member FromJson (_ : SimpleDU) =
json {
let! duA = Json.tryRead "a"
match duA with
| Some s -> return s
| None -> return SimpleDU.B
}
这可以编译,但当我尝试使用示例操作代码时:
let a = A
let b = B
let a2json = a |> Json.serialize
let (json2a:SimpleDU) = a2json |> Json.deserialize
let b2json = b |> Json.serialize
let (json2b:SimpleDU) = b2json |> Json.deserialize
json2a错误地返回SimpleDU.B您也可以向DU添加静态成员。在最后一段中,有一个链接提到一些DU的例子应该很快就会出现。但是,假设您不能等待,并且您更喜欢Chiron而不是Json.NET,或者这里是一个示例。可能还有其他方法,但我不熟悉Chiron的运算符,所以我决定使用一个计算表达式(从中窃取)。这样做的目的是,您可以进行模式匹配。因此,您也可以在更复杂的DU上进行模式匹配。如果你熟悉凯龙,我相信它会更地道。您可以看到Chiron本身正在使用DU,例如Json对象是map
#I @"..\packages\Chiron.6.1.0\lib\net40"
#I @"..\packages\Aether.8.0.2\lib\net35"
#I @"..\packages\FParsec.1.0.1\lib\net40-client"
#r "Chiron.dll"
#r "Aether.dll"
#r "Fparsec.dll"
open Aether
open Chiron
open Chiron.Operators
open FParsec
type SimpleDU =
|A of string
|B of int * bool
static member ToJson (x: SimpleDU) =
match x with
| A s -> Json.write "A" s
| B (i, b) -> Json.write "B" (i, b)
static member FromJson (_ : SimpleDU) =
json {
let! duA = Json.tryRead "A"
match duA with
| Some s -> return A s
| None ->
let! x = Json.read "B"
return B x
}
下面是它的工作原理:
let a = A "Jason"
let b = B (13,true)
let a2json = a |> Json.serialize //val Json = Object (map [("A", String "Jason")])
let (json2a:SimpleDU) = a2json |> Json.deserialize //val json2a : SimpleDU = A "Jason"
let b2json = b |> Json.serialize
let (json2b:SimpleDU) = b2json |> Json.deserialize
源代码中也有一些可能对您有用的示例:在我看来可能对您有所帮助。这个答案指向为有区别的联合定义ToString
和FromString
函数:
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
打开Microsoft.FSharp.Reflection
让toString(x:'a)=
匹配FSharpValue.GetUnionFields(x,typeof(s:string)=
匹配FSharpType.GetUnionCases类型无
您仍然需要从字符串(仅“A”或“B”)到完整的DU对象(例如,在s952163的
SimpleDU
示例中读取DU的其余数据),并且由于我还没有使用Chiron,在这方面我帮不了您多少忙。但这可能会给您一个起点。一个将A
序列化到对象的实现(映射[(“SimpleDU”,字符串“a”)])
而不是对象(映射[(“a”,Null)])
是:
#I @"..\packages\Chiron.6.1.0\lib\net40"
#I @"..\packages\Aether.8.1.2\lib\net35"
#r "Chiron.dll"
#r "Aether.dll"
open Chiron
type SimpleDU =
| A
| B
static member ToJson x =
Json.write "SimpleDU" <|
match x with
| A -> "a"
| B -> "b"
static member FromJson(_ : SimpleDU) =
json {
let! du = Json.tryRead "SimpleDU"
match du with
| Some "a" -> return A
| Some "b" -> return B
| Some x -> return! Json.error <| sprintf "%s is not a SimpleDU case" x
| _ -> return! Json.error "Not a SimpleDU JSON"
}
// val serializedA : Json = Object (map [("SimpleDU", String "a")])
let serializedA = A |> Json.serialize
let serializedB = B |> Json.serialize
let (a : SimpleDU) = serializedA |> Json.deserialize
let (b : SimpleDU) = serializedB |> Json.deserialize
let aMatches = a = A
let bMatches = b = B
let serializedABBAA = [ A; B; B; A; A ] |> Json.serialize
let (abbaa : SimpleDU list) = serializedABBAA |> Json.deserialize
let abbaaMatches = abbaa = [ A; B; B; A; A ]
// allFine = true
let allFine = aMatches && bMatches && abbaaMatches
let defects =
Array [ Object <| Map.ofList [ ("SimpleDU", String "c") ]
Object <| Map.ofList [ ("Foo", String "bar") ] ]
// attempt = Choice2Of2 "Not a SimpleDU JSON"
let (attempt : Choice<SimpleDU list, string>) = defects |> Json.tryDeserialize
#I@.\packages\Chiron.6.1.0\lib\net40
#I@“.\packages\ether.8.1.2\lib\net35”
#r“Chiron.dll”
#r“ether.dll”
开凯龙
类型SimpleDU=
|A
|B
静态成员tox=
Json.write“SimpleDU”“a”
|B->“B”
来自JSON的静态成员(uz:SimpleDU)=
json{
让!du=Json.tryRead“SimpleDU”
配
|有些“a”->返回a
|一些“b”->返回b
|Some x->return!Json.error return!Json.error“不是SimpleDU Json”
}
//val serializedA:Json=Object(映射[(“SimpleDU”,字符串“a”))
让serializedA=A |>Json.serialize
让serializedB=B |>Json.serialize
让(a:SimpleDU)=serializedA |>Json.deserialize
let(b:SimpleDU)=serializedB |>Json.deserialize
设aMatches=a=a
设b匹配=b=b
让serializedABBAA=[A;B;B;A;A]|>Json.serialize
let(abbaa:SimpleDU list)=序列化dabbaa |>Json.deserialize
让abbamatches=abbaa=[A;B;B;A;A]
//一切正常
让allFine=aMatches&&b匹配&&abbamatches
让缺陷=
Array[Object说到general f#Yan Cui发表了一篇关于它的文章。看看:你的意思是想使用一个选择(比如Choice1of2)类型还是只使用这个简单的DU?我现在无法测试它,但你可能可以在Json之后输入一些伪值。写“a”
像“a”
bu您可能也想返回s
。但感觉有点笨拙……您能看一下,看看这是否解决了您的问题吗。@s952163这越来越近了,非常感谢您的帮助,但它仍然不太有效。我再次编辑了问题,以显示我现在的状态。这意味着n match未能匹配“a”并返回无。尝试在没有B的情况下进行匹配,可能会出现错误。这可能与Chiron有关,也可能是let!语法。检查let!=duAI中的内容。假设有一种方法可以使用不同的语法进行模式匹配。顺便问一句,您是否锁定Chiron?