2016-04-12 30 views
4

Newtonsoft.Json.FSharp ile bir F # kayıt türü Json'a serileştiriyorum.İç içe geçmiş sözlüğün serileştirilmesi neden C# 'da bir istisna atar, ancak F #' da çalışır?

type Prices = Dictionary<string, decimal> 

type PriceList = {Id:string; Name:string; Date:DateTime; CurrencySymbol:string; Status:Status; Prices:Prices} 

let private converters : JsonConverter array = 
    [| BigIntConverter(); 
    GuidConverter(); 
    ListConverter(); 
    OptionConverter(); 
    MapConverter(); 
    TupleArrayConverter(); 
    UnionConverter(); 
    UriConverter(); 
    CultureInfoConverter() |] 

let private settings = JsonSerializerSettings (
         Converters = converters, 
         Formatting = Formatting.Indented, 
         NullValueHandling = NullValueHandling.Ignore) 

let serialize obj = JsonConvert.SerializeObject(obj, settings) 

JSON sonuç şudur:

{ 
    "Id": "PriceList20140201", 
    "Name": "PriceList", 
    "Date": "2014-02-01T00:00:00+01:00", 
    "CurrencySymbol": "€", 
    "Status": 0, 
    "Prices": { 
    "ItemCodeA": 512.4, 
    "ItemCodeB": 471.0 
    } 
} 

Ve bu serisini eğer F # Interactive içinde

JsonConvert.DeserializeObject<PriceList>(text) 

Sonucu çalışıyor: Ben Şimdi

val y : PriceList = 
{Id = "PriceList20140201"; 
Name = "PriceList"; 
Date = 01.04.2014 00:00:00; 
CurrencySymbol = "€"; 
Status = Sale; 
Prices = 
dict 
    [("ItemCodeA", 512.4M); ("ItemCodeB", 471.0M);...];} 

Newtonsoft kullanarak C# içinde deserialize etmek istiyorum .json

Bu JsonSerializationException sonuçlanır
public class PriceList 
{ 
    public string Id { get; set; } 
    public string Name { get; set; } 
    public DateTime Date { get; set; } 
    public string CurrencySymbol { get; set; } 
    public Status Status { get; set; } 
    public Prices Prices { get; set; } 
} 

public class Prices : Dictionary<string, decimal> 
{ 
} 
... 
JsonConvert.DeserializeObject<PriceList>(json) 

:

mevcut JSON dizi serisini edebilir (ör [1,2,3]) tip 'Halep.Logic.OfferManagement.Contracts.DataClasses.Pricing.Prices' türünde bir JSON nesnesi gerektirdiğinden (örn. {"Name": "value"}) için . Bu hatayı düzeltmek için JSON değerini JSON nesnesine (ör. {"Name": "value"}) dönüştürün veya serileştirilmiş tipi dizisine veya bir toplama arabirimini uygulayan bir türe (örn. ICollection, IList) değiştirin. JSON dizisinden serileştirilebilen liste. JsonArrayAttribute, bir JSON dizisinden serileştirilmiş 'a zorlamak için türe eklenebilir. Yol 'Fiyatlar', satır 7, konum 13.

İç içe geçmiş sözlükler için bir CustomConverter'a ihtiyacım olduğunu okudum. Ama bildiğim kadarıyla sürüm 6.0'dan beri mümkün olmalıdır. özel bir dönüştürücü olmadan. Şu anda 8.0.3 kullanıyorum. Neden F # içinde çalışıyor ama C# değil? C# nesne yapısı yanlış mı?

PriceList'i doğrudan Sözlük'le değil aynı sonuçla değiştirmeyi denedim.

public class PriceList 
{ 
    public string Id { get; set; } 
    public string Name { get; set; } 
    public DateTime Date { get; set; } 
    public string CurrencySymbol { get; set; } 
    public Status Status { get; set; } 
    public Dictionary<string, decimal> Prices { get; set; } 
} 

Ve neredeyse aynı İstisna var:

akım JSON dizi serisini Can (örneğin [1,2,3 son cümle bu çalıştı anlamına Güncelleme

]) türüne 'System.Collections.Generic.Dictionary`2 [System.String, System.Decimal]' türünde bir JSON nesnesi (örn. {"name": "value"}) için deserializ gereklidir. e doğru. Bu hatayı düzeltmek için JSON değerini JSON nesnesine (ör. {"Name": "value"}) dönüştürün veya serileştirilmiş tipi dizisine veya bir toplama arabirimini uygulayan bir türe (örn. ICollection, IList) değiştirin. JSON dizisinden serileştirilebilen liste. JsonArrayAttribute, bir JSON dizisinden serileştirilmiş 'a zorlamak için türe eklenebilir. Yol 'Fiyatlar', satır 7, pozisyon 13.

Güncelleme 2: Çözüm Bu kod çalışır . @JustinNiessner'ın son yorumu çözüme yol açtı.

{ 
    "Id": "PriceList20140201", 
    "Name": "PriceList", 
    "Date": "2014-02-01T00:00:00+01:00", 
    "CurrencySymbol": "€", 
    "Status": 0, 
    "Prices": [ 
    "ItemCodeA": 512.4, 
    "ItemCodeB": 471.0 
    ] 

}

+0

Satın almayı denediğiniz JSON nesnesi nedir? PriceList, örnek kodunuzda bir liste değildir, bu nedenle bir koleksiyonu bir koleksiyonla alakası olmayan bir türe dönüştürebilirsiniz. – dustinmoris

+0

F # ile serileştirmenin sonucu olan ikinci kod snippet'ini seri hale getirmeye çalışıyorum. PriceList sadece F #/C sınıfındaki tiptir # – KCT

+0

F # kodunuz Sözlük kullanır, C# kodunuz fiyatları kullanır. Sözlük de yap. –

cevap

5

type Prices = Dictionary<string, decimal> bir tip F # da kısaltma yerine olarak Dictionary<string, decimal> devralan yeni bir sınıf oluşturma: Sorun giriş aslında [] yerine} {arasında içermektedir ve bu oldu C# kodu yapar: Eğer ikisi arasındaki seri kaldırma farklılıkları görüyoruz neden

F# Type Abbreviations

budur.

Bunu C# içinde düzeltebileceğiniz iki yol vardır. İlk using yönergesi ile benzer bir tip takma adı oluşturmak olacaktır:

using Prices = System.Collections.Generic.Dictionary<string, object>; 

diğer basitçe PriceList sınıf tanımında Decimal<string, decimal> ile türünü değiştirmek şeklinde olur: o zaman

public class PriceList 
{ 
    public string Id { get; set; } 
    public string Name { get; set; } 
    public DateTime Date { get; set; } 
    public string CurrencySymbol { get; set; } 
    public Status Status { get; set; } 
    public Dictionary<string, decimal> Prices { get; set; } 
} 

Ve C# Desserialization, F # ile aynı şekilde çalışacaktır.

+0

Evet, Bu, Fiyatlar yerine, fiyatların kullanıldığı anlamına gelir. Anladığım kadarıyla C# 'da aynısını yapıyorum. Sadece sözlüğü sınıftan türeterek. Neyse soruyu başka bir şekilde sorabilirim. İkinci snippet'i (json) serileştirmek için C# nesnesinin yapısı nedir? Fiyatlar bir sözlük olmalı . Ne yazık ki işe yaramıyor – KCT

+1

@KCT - "Ondalık " öğesinden devralma ve yeni bir alt öğe türü oluşturmak, ana türün farklı bir adla eşleştirilmesinden çok farklı. Sadece "Ondalık " den miras aldığınız için, bunun aynı şekilde serileştirilebileceğini garanti etmez. –

+0

@KCT - Her iki durumda da, cevabımı C# takma adlarıyla eşleştirdim. –