首页 > 解决方案 > 反序列化为 F# 中的枚举选项

问题描述

几天前,我发布了一个关于在 F# 中使用枚举进行反序列化的问题。问题就在这里:F# 与 C# 中的反序列化

答案指向了 Isaac Abraham 编写的一些代码,位于:https ://gist.github.com/isaacabraham/ba679f285bfd15d2f53e

但是我面临另一个问题:

如果要反序列化的对象具有“枚举选项”类型的对象,则反序列化将失败,而如果类型只是“枚举”,它将起作用。

一个最小的例子:

type TestType =
    | A = 0
    | B = 1

type TestObjectA =
      {
           test : TestType
      }

type TestObjectB =
     {
         test : TestType option
     }


let x = "{\"test\":\"A\"}"
let TestA = Deserialize<TestObjectA> x // will work
let TestB = Deserialize<TestObjectB> x // will fail

大型反序列化代码位于:https ://pastebin.com/95JZLa6j

我把整个代码放在一个小提琴中:https ://dotnetfiddle.net/0Vc0Rh 但它不能从那里运行,因为他们支持的 F# 版本不接受'object'关键字。

所以,我的问题是:为什么我不能在枚举上使用选项类型,但它适用于其他类型?附带说明一下,由于我对 F# 还很陌生,所以我并没有完全理解 Isaac 的代码,尽管我花了一些时间来研究它并尝试对其进行故障排除。

我的理解是这一行:|> Seq.map (fun (value, propertyInfo) -> Convert.ChangeType(value, propertyInfo.PropertyType))

将尝试将类型转换为正确的枚举,而不是枚举选项。

作为一个额外的问题,是否有一个可行的解决方案可以使用枚举进行完全惯用的反序列化?(不经过空类型)

标签: f#json.net

解决方案


open System.IO

type TestType =
    | A = 0
    | B = 1

type TestObjectB =
     {
         test : TestType option
     }

let jsonSerializeToString obj = 
    use writer = new StringWriter()
    let ser =  new Newtonsoft.Json.JsonSerializer()
    ser.Formatting <- Newtonsoft.Json.Formatting.Indented
    ser.Serialize(writer, obj)
    writer.ToString()

let jsonDeserializeFromString str =
    Newtonsoft.Json.JsonConvert.DeserializeObject<TestObjectB>(str)

let Test obj = 
    let str = jsonSerializeToString obj
    let obj' = jsonDeserializeFromString str
    obj'

[<EntryPoint>]
let main argv =
    { test = Some TestType.B } |> Test |> ignore
    { test = None } |> Test |> ignore
    0

注意:如果您需要序列化大量对象集合,请将它们流式传输到文件而不是内存中的字符串以避免 OutOfMemoryException。喜欢use writer = File.CreateText(filePath)


推荐阅读