2014-11-23 233 views
2

使用Newtonsoft.Json,最新的版本(6.0.6 =)我得到以下錯誤:Newtonsoft無法反序列化一個空的F#序列?

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 

回答

4

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

但是F#並沒有讓他們特別容易。例如,一個用Seq.empty定義的空seq不僅僅是一個IEnumerable<T>,它是一個特定的可執行實現EmptyEnumerable<T>,這似乎引發了序列化 - 很可能是因爲沒有合適的構造函數。從後鏈接到您:如果您初始化序列這樣反而

To all future creators of immutable .NET collections: If your collection of T has a constructor that takes IEnumerable then Json.NET will automatically work when deserializing to your collection, otherwise you're all out of luck.

,也許行爲會有所不同:

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

但是,這是雞蛋裏挑骨頭,這裏實際的答案很簡單 - 唐序列化序列。只需使用像數組這樣的具體,行爲良好的類型即可。類型越簡單,在序列化或互操作時就越不容易讓你頭疼。

+0

謝謝,我已經嘗試過,但是沒有奏效。所以,我想這只是沒有實現。必須切換回數組。 – halcwb 2014-11-23 19:36:58

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 

所以,只要你使用具有可識別的構造函數,例如列表的類型構建你的序列,可將對象deserialised。奇怪的是,將序列初始化爲一個數組,然後將其轉換爲一個序列,就像使用列表來排序示例(通過)一樣,失敗。

2

設置JsonSerializerSettings.ObjectCreationHandling = ObjectCreationHandling.Replace將解決此錯誤。