2011-07-27 41 views
14

Tôi có một JSON:json.net: xác định chuyển đổi cho các phím từ điển

{ 
    "data": { "A": 5, "B": 6 }, 
    "foo": "foo", 
    "bar": "bar" 
} 

tôi cần phải deserialize dữ liệu vào một lớp học:

public Dictionary<MyEnum, int> Data { get; set; } 
public string Foo { get; set; } 
public string Bar { get; set; } 

Nhưng MyEnum giá trị là CodeA, và thay vì CodeB chỉ đơn giản là AB tương ứng.

Tôi có Trình chuyển đổi tùy chỉnh có thể xử lý chuyển đổi. Nhưng làm cách nào để chỉ định một JsonConverter để sử dụng với các phím Từ điển?

Trả lời

13

Tôi tin rằng cách duy nhất là tạo JsonConverter cho toàn bộ loại Dictionary<MyEnum, int> hoặc Dictionary<MyEnum, T>.

Khóa từ điển không được coi là giá trị và sẽ không được chạy qua JsonConverters. TypeConverters sẽ là một giải pháp, nhưng chuỗi mặc định để chuyển đổi enum sẽ nhập trước khi nó nhìn vào TypeConverters.

Vì vậy ... Tôi không nghĩ rằng nó có thể được thực hiện theo bất kỳ cách nào khác.

EDIT:

Không kiểm tra đầy đủ, nhưng tôi sử dụng một cái gì đó như thế này trong một dự án của tôi:

public class DictionaryWithSpecialEnumKeyConverter : JsonConverter 
{ 
    public override bool CanWrite 
    { 
     get { return false; } 
    } 

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 
    { 
     throw new NotSupportedException(); 
    } 

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 
    { 
     if (reader.TokenType == JsonToken.Null) 
      return null; 

     var valueType = objectType.GetGenericArguments()[1]; 
     var intermediateDictionaryType = typeof(Dictionary<,>).MakeGenericType(typeof(string), valueType); 
     var intermediateDictionary = (IDictionary)Activator.CreateInstance(intermediateDictionaryType); 
     serializer.Populate(reader, intermediateDictionary); 

     var finalDictionary = (IDictionary)Activator.CreateInstance(objectType); 
     foreach (DictionaryEntry pair in intermediateDictionary) 
      finalDictionary.Add(Enum.Parse(MyEnum, "Code" + pair.Key, false), pair.Value); 

     return finalDictionary; 
    } 

    public override bool CanConvert(Type objectType) 
    { 
     return objectType.IsA(typeof(IDictionary<,>)) && 
       objectType.GetGenericArguments()[0].IsA<MyEnum>(); 
    } 
} 

Bạn sẽ cần helper ít này:

public static bool IsA(this Type type, Type typeToBe) 
    { 
     if (!typeToBe.IsGenericTypeDefinition) 
      return typeToBe.IsAssignableFrom(type); 

     var toCheckTypes = new List<Type> { type }; 
     if (typeToBe.IsInterface) 
      toCheckTypes.AddRange(type.GetInterfaces()); 

     var basedOn = type; 
     while (basedOn.BaseType != null) 
     { 
      toCheckTypes.Add(basedOn.BaseType); 
      basedOn = basedOn.BaseType; 
     } 

     return toCheckTypes.Any(x => x.IsGenericType && x.GetGenericTypeDefinition() == typeToBe); 
    } 

Hy vọng nó hoạt động cho bạn.

+1

Điều này đặc biệt hữu ích khi sử dụng Json.Net trên nền tảng điện thoại di động kể từ TypeConverters không được hỗ trợ, và điều này tiếp cận là cần thiết cho ví dụ. cấu trúc như các phím quá. –

+0

cách sử dụng trình chuyển đổi của bạn một cách chính xác? Tôi có json tương tự. Và tôi muốn loại bỏ nó vào lớp tiếp theo: 'lớp công khai InsightsReportDataMetric { [JsonProperty (" programs ")] Public InsightsReportDataPrograms [] Programs {get; bộ; } = InsightsReportDataPrograms mới [0]; [JsonProperty ("ngày")] chuỗi công cộng Ngày {get; bộ; } [JsonConverter (typeof (InsightsMetricConverter))] từ điển công khai MetricValues ​​{get; bộ; } } 'nhưng trong trình chuyển đổi mẫu của tôi không bao giờ đạt được ... – demo

0

Dưới đây là một giải pháp chung cho vấn đề của việc sử dụng json với từ điển với bất kỳ loại hình chính:

[JsonObject] 
public class MyKeyValuePair<TKey, TValue> 
{ 
    public TKey MyKey; 

    public TValue MyValue; 

    [JsonConstructor] 
    public MyKeyValuePair() 
    { 

    } 

    public MyKeyValuePair(TKey t1, TValue t2) 
    { 
     MyKey = t1; 
     MyValue = t2; 
    } 
} 



[JsonObject] 
public class MyDictionaty<TKey, TValue> 

{ 
    public ICollection<MyKeyValuePair<TKey, TValue>> Collection; 

    [JsonConstructor] 
    public MyDictionaty() 
    { 

    } 
    public MyDictionaty(Dictionary<TKey, TValue> refund) 
    { 
     Collection = BuildMyKeyValuePairCollection(refund); 
    } 
    internal Dictionary<TKey, TValue> ToDictionary() 
    { 
     return Collection.ToDictionary(pair => pair.MyKey, pair => pair.MyValue); 
    } 

    private ICollection<MyKeyValuePair<TKey, TValue>> BuildMyKeyValuePairCollection(Dictionary<TKey, TValue> refund) 
    { 
     return refund.Select(o => new MyKeyValuePair<TKey, TValue>(o.Key, o.Value)).ToList(); 
    } 
} 




[JsonObject] 
public class ClassWithDictionary 
{ 
    [JsonProperty] 
    private readonly MyDictionary<AnyKey, AnyValue> _myDictionary; 

    private Dictionary<AnyKey, AnyValue> _dic; 

    [JsonConstructor] 
    public ClassWithDictionary() 
    { 

    } 
    public ClassWithDictionary(Dictionary<AnyKey, AnyValue> dic) 
    { 
     _dic= dic; 
     _myDictionary = new MyDictionaty<AnyKey, AnyValue>(dic); 
    } 

    public Dictionary<AnyKey, AnyValue> GetTheDictionary() 
    { 
     _dic = _dic??_myDictionary.ToDictionary(); 
     return _dic; 
    } 
} 
+0

cách sử dụng giải pháp chung này? – sky91

Các vấn đề liên quan