2012-10-05 17 views
25

Json.Net zazwyczaj serializuje Dictionary<k,v> do kolekcji;Json.Net - Słownik szeregowania jako macierz (par wartości klucza)

"MyDict": { 
    "Apples": { 
    "Taste": 1341181398, 
    "Title": "Granny Smith", 
    }, 
    "Oranges": { 
    "Taste": 9999999999, 
    "Title": "Coxes Pippin", 
    }, 
} 

Co jest wspaniałe. A od rozejrzenia się po SO wydaje się, że większość ludzi chce. Jednak w tym konkretnym przypadku chcę serializować między moim Dictionary<k,v> a formatem Array;

"MyDict": [ 
    "k": "Apples", 
    "v": { 
     "Taste": 1341181398, 
     "Title": "Granny Smith", 
    } 
    }, 
    "k:": "Oranges", 
    "v:": { 
     "Taste": 9999999999, 
     "Title": "Coxes Pippin", 
    } 
    }, 
] 

Czy istnieje prosty sposób, aby to zrobić z moim istniejącym typem pola? Czy istnieje atrybut, który mogę opisać na przykład?

Odpowiedz

21

Ach, okazuje się, że jest to tak proste, jak miałem nadzieję. Mój Dictionary<k,v> jest już podklasowany i znalazłem, że mogę dodać adnotację do niego z [JsonArrayAttribute]. To daje mi dokładnie taki format, jakiego potrzebuję;

"MyDict": [ 
    { 
    "Key": "Apples", 
    "Value": { 
     "Taste": 1341181398, 
     "Title": "Granny Smith", 
    } 
    }, 
    { 
    "Key:": "Oranges", 
    "Value:": { 
     "Taste": 9999999999, 
     "Title": "Coxes Pippin", 
    } 
    }, 
] 
11

Dla tego przykładu użyję dictonary:

var myDict = new Dictionary<string,string>() { 
    {"a","123"}, 
    {"b","234"}, 
    {"c","345"} 
}; 

który serializes (z Newtonsoft.Json.JsonConvert.SerializeObject(myDict)) do:

{"a":"123","b":"234","c":"345"} 

można zrobić transformacji przy użyciu LINQ aby utworzyć anonimowy obiekt i serializować to:

var myDictTransformed = from key in myDict.Keys 
         select new { k = key, v = myDict[key] }; 

Albo można użyć prawdziwego obiektu

class MyDictEntry 
{ 
    public string k { get; set; } 
    public string v { get; set; } 
} 

i albo powyżej albo alternatywą składni LINQ:

var myDictTransformed = myDict.Keys.AsEnumerable() 
         .Select(key => new MyDictEntry{ 
          k = key, 
          v = myDict[key] 
         }); 

Tak czy inaczej, to serializes do:

[ 
    {"k":"a", "v":"123"}, 
    {"k":"b", "v":"234"}, 
    {"k":"c", "v":"345"} 
] 

.NET Fiddle link: https://dotnetfiddle.net/LhisVW

1

Odpowiedź Gregmac była pomocna, ale nie działała. Oto ten sam pomysł ... bez kalamburów.

var dictionaryTransformed = dictionary.Select(item => item.Key).Select(i => 
         new {Key = i, Value = dictionary[i] }); 

lub oczywiście

var dictionaryTransformed = dictionary.Select(item => 
         new {item.Key, Value = dictionary[item.Key] }); 

Następnie do JSON

var json = (new JavaScriptSerializer()).Serialize( 
         new { Container = dictionaryTransformed.ToArray() }) 
27

Innym sposobem osiągnięcia tego celu jest stosowanie niestandardowych ContractResolver. W ten sposób nie musisz podklasę Dictionary<K,V> ani zastosować transformacji przy każdym serializowaniu, co sugerują inne odpowiedzi.

Poniższy rezolwer spowoduje wszystkie słowniki być szeregowane jako tablicę obiektów z „klucz” i „wartość” Właściwości:

class DictionaryAsArrayResolver : DefaultContractResolver 
{ 
    protected override JsonContract CreateContract(Type objectType) 
    { 
     if (objectType.GetInterfaces().Any(i => i == typeof(IDictionary) || 
      (i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IDictionary<,>)))) 
     { 
      return base.CreateArrayContract(objectType); 
     } 

     return base.CreateContract(objectType); 
    } 
} 

Aby korzystać z rozpoznawania nazw, dodaj go do swojej JsonSerializerSettings, a następnie przekazać ustawienia do JsonConvert.SerializeObject() tak:

JsonSerializerSettings settings = new JsonSerializerSettings(); 
settings.ContractResolver = new DictionaryAsArrayResolver(); 

string json = JsonConvert.SerializeObject(obj, settings); 

Powyżej znajduje się working demo.

+0

Praca dla serializacji, teraz Jak deserializować ten sam obiekt – MSTdev

+0

@MSTdev Ten sam pomysł, użyj 'JsonConvert.DeserializeObject' i pamiętaj, aby przepuścić' JsonSerializerSettings' z resolver do tej metody. Zaktualizowałem skrzypce, aby zademonstrować. –

+0

@ BrianRogers proszę sprawdzić mój szczegółowy problem http://stackoverflow.com/questions/32473308/serialize-deserialization-issue-on-newton-json-for-imiction-mictionklass-li – MSTdev

7

Najprostszym rozwiązaniem, jakie znalazłem, jest zamiana Twojego Dictionary<string, string> na List<KeyValuePair<string, string>>. Następnie JSON.NET przekształca swój List w tablicę obiektów w postaci { Key: 'keyname', Value: 'value' }. Działa to dobrze, jeśli zaakceptujesz wymaganą zmianę modelu i nie chcesz podklasować swojej Dictionary.

+0

Korzystanie z metod rozszerzenia ToList() lub ToArray() sprawia, że łatwo. –

Powiązane problemy