Newtonsoft不能反序列化一个空的F#序列?

时间:2014-11-23 15:58:20

标签: f# json.net

使用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 

3 个答案:

答案 0 :(得分:4)

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

但是F#并不能让它们特别容易。例如,使用Seq.empty定义的空seq不仅仅是IEnumerable<T>,它是一个特殊的可枚举实现EmptyEnumerable<T>,这似乎摒弃了序列化 - 很可能因为&# 39;没有合适的构造函数。从您链接到的帖子:

  

对于所有未来的不可变.NET集合的创建者:如果你的T集合有一个带有IEnumerable的构造函数,那么Json.NET将在反序列化到你的集合时自动工作,否则你一切都运气不好。

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

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

但是那个分裂的头发,这里的实际答案很简单 - 不要序列化seqs。只需使用像数组这样具体,表现良好的类型。类型越简单,在进行序列化或互操作时给头疼的可能性就越小。

答案 1 :(得分:2)

设置JsonSerializerSettings.ObjectCreationHandling = ObjectCreationHandling.Replace将解决此错误。

答案 2 :(得分:0)

我喜欢使用像数组这样的简单类型的概念,只是我想使用相同的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

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