2013-02-15 13 views
26

Tôi đang sử dụng Json.Net cho serialization. Tôi có một lớp học với một từ điển:Làm thế nào để serialize một từ điển như là một phần của đối tượng cha mẹ của nó bằng cách sử dụng Json.Net

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

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

Tôi có thể bằng cách nào đó serialize đối tượng này để có được những JSON sau

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

nơi "key1", "khóa2" là chìa khóa trong từ điển?

Trả lời

34

Nếu bạn đang sử dụng Json.Net 5.0.5 hoặc mới hơn và bạn sẵn sàng để thay đổi kiểu của từ điển của bạn từ Dictionary<string, string> để Dictionary<string, object>, sau đó một cách dễ dàng để thực hiện những gì bạn muốn là thêm thuộc tính [JsonExtensionData] đến tài sản từ điển của bạn như thế này :

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

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

Các khóa và giá trị của từ điển được đánh dấu sẽ được tuần tự hóa như một phần của đối tượng gốc. Tiền thưởng là nó hoạt động trên deserialization là tốt: bất kỳ tài sản trong JSON mà không phù hợp với các thành viên của lớp sẽ được đặt vào từ điển.

7

Triển khai JsonConverter lớp được cấp: lớp CustomCreationConverter nên được sử dụng làm lớp cơ sở để tạo đối tượng tùy chỉnh tùy chỉnh.

Dự thảo phiên bản của bộ chuyển đổi (xử lý lỗi có thể được cải thiện khi bạn muốn):

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 
} 

Khách hàng mã:

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

Xin lưu ý: có một vụ va chạm tiềm năng giữa tên tài sản và chìa khóa tên của từ điển.

+0

Cảm ơn bạn. Chỉ có một bổ sung: Tôi nghĩ rằng tốt hơn có được các thuộc tính từ JsonContract '(JsonObjectContract) serializer.ContractResolver.ResolveContract (typeof (Test))'. Sử dụng cách này có thể nhận được các giá trị JsonPropertyAttribute. – Nataly

1

Bạn có thể tạo công cụ chuyển đổi này và sau đó gán nó cho tài sản của bạn. Mất bit và phần của các giải pháp được đề xuất.

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

Sau đó, sử dụng nó trong lớp poco của bạn.

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

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