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