2013-02-15 15 views

Odpowiedz

34

Jeśli używasz Json.Net 5.0.5 lub nowszej i jesteś gotów zmienić rodzaj słownika z Dictionary<string, string> do Dictionary<string, object>, następnie jeden prosty sposób, aby osiągnąć to, co chcesz, aby dodać atrybut [JsonExtensionData] do słownika nieruchomości jak to :

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

    [JsonExtensionData] 
    public Dictionary<string, object> Y { get; set; } 
} 

Klucze i wartości zaznaczonego słownika zostaną następnie przekształcone do postaci szeregowej jako część obiektu nadrzędnego. Dodatkową korzyścią jest to, że działa również na deserializacji: wszelkie właściwości w JSON, które nie pasują do członków klasy, zostaną umieszczone w słowniku.

7

Wdrożenie JsonConverter pochodzące z A klasy: klasa CustomCreationConverter powinien być stosowany jako klasy bazowej, aby utworzyć niestandardowego obiektu.

Projekt wersja konwertera (obsługi błędów można poprawić, jak chcesz):

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 
} 

kod Klient:

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); 

Uwaga: istnieje ryzyko kolizji nazw właściwości i klucz nazwy słownika.

+0

Dziękuję. Tylko jeden dodatek: Myślę, że lepiej uzyskać właściwości z JsonContract '(JsonObjectContract) serializer.ContractResolver.ResolveContract (typeof (Test))'. W ten sposób można uzyskać wartości JsonPropertyAttribute. – Nataly

1

Możesz utworzyć ten konwerter, a następnie przypisać go do swojej nieruchomości. Wybrano fragmenty proponowanych rozwiązań.

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)); 
     } 
    } 

Następnie użyj go w swojej klasie poco.

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

     [JsonProperty("properties")] 
     [JsonConverter(typeof(DictionaryToJsonObjectConverter))] 
     public IDictionary<string, string> Properties { get; set; } 
    } 
Powiązane problemy