2013-02-15 12 views
26

Sto usando Json.Net per la serializzazione. Ho una classe con un dizionario:Come serializzare un dizionario come parte del suo oggetto padre usando Json.Net

public class Test 
{ 
    public string X { get; set; } 

    public Dictionary<string, string> Y { get; set; } 
} 

Posso in qualche modo serializzare questo oggetto per ottenere il seguente JSON

{ 
    "X" : "value", 
    "key1": "value1", 
    "key2": "value2" 
} 

dove "key1", "key2" sono le chiavi del dizionario?

risposta

34

Se stai usando Json.Net 5.0.5 o versione successiva e si è disposti a cambiare il tipo di dizionario da Dictionary<string, string> a Dictionary<string, object>, quindi un modo semplice per realizzare ciò che si desidera è di aggiungere l'attributo [JsonExtensionData] alla vostra proprietà dizionario come questo :

Le chiavi e i valori del dizionario contrassegnato verranno serializzati come parte dell'oggetto padre. Il vantaggio è che funziona anche con la deserializzazione: qualsiasi proprietà nel JSON che non corrisponde ai membri della classe verrà inserita nel dizionario.

7

Implementare JsonConverter classe -derived: la classe CustomCreationConverter dovrebbe essere usata come classe base per creare un oggetto personalizzato .

Progetto versione del convertitore (gestione degli errori può essere migliorata a piacere):

internal class TestObjectConverter : CustomCreationConverter<Test> 
{ 
    #region Overrides of CustomCreationConverter<Test> 

    public override Test Create(Type objectType) 
    { 
     return new Test 
      { 
       Y = new Dictionary<string, string>() 
      }; 
    } 

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 
    { 
     writer.WriteStartObject(); 

     // Write properties. 
     var propertyInfos = value.GetType().GetProperties(); 
     foreach (var propertyInfo in propertyInfos) 
     { 
      // Skip the Y property. 
      if (propertyInfo.Name == "Y") 
       continue; 

      writer.WritePropertyName(propertyInfo.Name); 
      var propertyValue = propertyInfo.GetValue(value); 
      serializer.Serialize(writer, propertyValue); 
     } 

     // Write dictionary key-value pairs. 
     var test = (Test)value; 
     foreach (var kvp in test.Y) 
     { 
      writer.WritePropertyName(kvp.Key); 
      serializer.Serialize(writer, kvp.Value); 
     } 
     writer.WriteEndObject(); 
    } 

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 
    { 
     JObject jsonObject = JObject.Load(reader); 
     var jsonProperties = jsonObject.Properties().ToList(); 
     var outputObject = Create(objectType); 

     // Property name => property info dictionary (for fast lookup). 
     var propertyNames = objectType.GetProperties().ToDictionary(pi => pi.Name, pi => pi); 
     foreach (var jsonProperty in jsonProperties) 
     { 
      // If such property exists - use it. 
      PropertyInfo targetProperty; 
      if (propertyNames.TryGetValue(jsonProperty.Name, out targetProperty)) 
      { 
       var propertyValue = jsonProperty.Value.ToObject(targetProperty.PropertyType); 
       targetProperty.SetValue(outputObject, propertyValue, null); 
      } 
      else 
      { 
       // Otherwise - use the dictionary. 
       outputObject.Y.Add(jsonProperty.Name, jsonProperty.Value.ToObject<string>()); 
      } 
     } 

     return outputObject; 
    } 

    public override bool CanWrite 
    { 
     get { return true; } 
    } 

    #endregion 
} 

Codice cliente:

var test = new Test 
    { 
     X = "123", 
     Y = new Dictionary<string, string> 
      { 
       { "key1", "value1" }, 
       { "key2", "value2" }, 
       { "key3", "value3" }, 
      } 
    }; 

string json = JsonConvert.SerializeObject(test, Formatting.Indented, new TestObjectConverter()); 
var deserializedObject = JsonConvert.DeserializeObject<Test>(json); 

Si prega di notare: c'è un potenziale collisione tra nomi di proprietà e la chiave nomi del dizionario.

+0

Grazie. Solo una aggiunta: penso che sia meglio ottenere le proprietà da JSONContract '(JsonObjectContract) serializer.ContractResolver.ResolveContract (typeof (Test))'. Utilizzare in questo modo può ottenere valori JsonPropertyAttribute. – Nataly

1

È possibile creare questo convertitore e quindi assegnarlo alla proprietà. Ha preso bit e pezzi di soluzioni proposte.

public class DictionaryToJsonObjectConverter : JsonConverter 
    { 
     public override bool CanConvert(Type objectType) 
     { 
      return typeof(IDictionary<string, string>).IsAssignableFrom(objectType); 
     } 

     public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 
     { 
      throw new NotImplementedException(); 
     } 

     public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 
     { 
      writer.WriteRawValue(JsonConvert.SerializeObject(value, Formatting.Indented)); 
     } 
    } 

Quindi usarlo nella tua classe poco.

public class Poco 
{ 
     [JsonProperty("myid")] 
     public string Id{ get; set; } 

     [JsonProperty("properties")] 
     [JsonConverter(typeof(DictionaryToJsonObjectConverter))] 
     public IDictionary<string, string> Properties { get; set; } 
    } 
Problemi correlati