【问题标题】:Newtonsoft cannnot deserialize an empty F# sequence?Newtonsoft 不能反序列化一个空的 F# 序列?
【发布时间】:2014-11-23 15:58:20
【问题描述】:

使用 Newtonsoft.Json,最新版本 (=6.0.6) 我收到以下错误:

Cannot create and populate list type Microsoft.FSharp.Core.CompilerServices.RuntimeHelpers+EmptyEnumerable`1[System.String]

但是在post 中宣布 Newtonsoft.Json 将完全支持 Fsharp 类型?

当我将违规类型更改为常规数组时,一切正常。

代码:

type Prescription () = 
    member val Id = "" with get, set
    member val Status = new PrescriptionStatus() with get, set
    member val Prescriber = new Prescriber() with get, set
    member val Indications = [||] : string[] with get, set

当我将指示更改为:

    member val Indications = Seq.empty : string seq with get, set

我遇到了错误。

另外,当我初始化一个实际上是可枚举的数组时,它不能被构造:

member val Indications : string seq = [||] |> Array.toSeq with get, set 

【问题讨论】:

    标签: f# json.net


    【解决方案1】:

    我猜答案是,Newtonsoft.Json 不完全支持 F# 类型。

    但 F# 并没有让支持它们变得特别容易。例如,用Seq.empty 定义的空seq 不仅仅是IEnumerable<T>,它是一个特定的可枚举实现EmptyEnumerable<T>,这似乎会导致序列化失败——很可能是因为它上面没有合适的构造函数。从您链接到的帖子中:

    致所有未来不可变 .NET 集合的创建者:如果您的 T 集合有一个采用 IEnumerable 的构造函数,那么 Json.NET 将在反序列化到您的集合时自动工作,否则您将完全不走运。

    如果你像这样初始化你的序列,也许行为会有所不同:

    member val Indications = Seq.ofArray [||] : string seq with get, set
    

    但这很麻烦,这里的实际答案很简单——不要序列化 ​​seq。只需使用具体的、行为良好的类型,如数组。类型越简单,在进行序列化或互操作时让您头疼的可能性就越小。

    【讨论】:

    • 谢谢,我已经试过了,但是没有用。所以,我想这只是没有实现。必须切换回数组。
    【解决方案2】:

    设置JsonSerializerSettings.ObjectCreationHandling = ObjectCreationHandling.Replace 将修复此错误。

    【讨论】:

      【解决方案3】:

      我喜欢使用像数组这样的简单类型的概念,只是我想使用相同的 DTO 来映射到 Linq 查询中的 IQueryable。所以,在这方面,数组不是一种选择。

      幸运的是,经过一些测试,它很简单:

      #load ".\Scripts\load-project.fsx"
      
      #time
      
      open System
      open System.Collections.Generic
      
      open Newtonsoft.Json
      
      [<CLIMutable>]
      type Test1 =
          {
              Strings : string seq
          }
      
      type Test2 () =
          member val Strings = Seq.empty : IEnumerable<string> with get, set
      
      type Test3 () =
          member val Strings = Seq.empty : String seq with get, set
      
      type Test4 () =
          member val Strings : IEnumerable<string> = Seq.empty : IEnumerable<string> with get, set
      
      type Test5 () =
          member val Strings : IEnumerable<string> = [] |> List.toSeq : IEnumerable<string> with get, set
      
      type Test6 () =
          member val Strings = [] |> List.toSeq : string seq with get, set
      
      let test1 = { Strings = Seq.empty }
      let test2 = new Test2 ()
      let test3 = new Test3 () 
      let test4 = new Test4 () 
      let test5 = new Test5 () 
      let test6 = new Test6 () 
      
      let json1 = JsonConvert.SerializeObject(test1)
      let json2 = JsonConvert.SerializeObject(test2)
      let json3 = JsonConvert.SerializeObject(test3)
      let json4 = JsonConvert.SerializeObject(test4)
      let json5 = JsonConvert.SerializeObject(test5)
      let json6 = JsonConvert.SerializeObject(test6)
      
      let deserialized1 = JsonConvert.DeserializeObject<Test1>(json1) // Fails
      let deserialized2 = JsonConvert.DeserializeObject<Test2>(json2) // Fails
      let deserialized3 = JsonConvert.DeserializeObject<Test3>(json3) // Fails
      let deserialized4 = JsonConvert.DeserializeObject<Test4>(json4) // Fails
      let deserialized5 = JsonConvert.DeserializeObject<Test5>(json5) // Passes
      let deserialized6 = JsonConvert.DeserializeObject<Test5>(json6) // Passes
      

      因此,只要您使用具有可识别构造函数的类型(例如列表)构造序列,就可以反序列化对象。奇怪的是,将序列初始化为数组,然后将其转换为序列,就像列表到序列示例(通过)一样,失败了。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-06-06
        • 1970-01-01
        • 2016-11-28
        • 2016-09-10
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多