2016-03-26 4 views
0

У меня есть OrderedDictionary с int ключами и System.Drawing.Rectangle значениями. JSON.NET не будет сериализовать OrderedDictionary ... он возвращает пустой объект. Я написал собственный конвертер, но я подумал, есть ли более простой способ. Думая, что JSON.NET может использовать присутствие типизированного перечислителем в качестве триггера использовать его встроенный код для сериализации и десериализации Dictionary<TKey, TValue> Я попытался это:Использование JSON.NET с OrderedDictionary

class Program 
{ 
    static void Main(string[] args) 
    { 
     var test = new OrderedDictionary<int, Rectangle>(); 
     test.Add(1, new Rectangle(0, 0, 50, 50)); 
     test.Add(42, new Rectangle(1, 1, 1, 1)); 

     string s = JsonConvert.SerializeObject(test); 
     var deserialized = JsonConvert.DeserializeObject<OrderedDictionary<int, Rectangle>>(s); 

     var someRect = deserialized[(object)1]; // someRect is null 
     var someOtherRect = (Rectangle)deserialized["1"]; // InvalidCastException 
    } 
} 

public class OrderedDictionary<TKey, TValue> : OrderedDictionary, IEnumerable<KeyValuePair<TKey, TValue>> 
{ 
    IEnumerator<KeyValuePair<TKey, TValue>> IEnumerable<KeyValuePair<TKey, TValue>>.GetEnumerator() 
    { 
     foreach (TKey key in Keys) 
     { 
      yield return new KeyValuePair<TKey, TValue>(key, (TValue)this[key]); 
     } 
    } 
} 

Сериализация работает отлично. Однако, когда я десериализую, ключи в словаре становятся строками, а Rectangle s - JObject s, которые не могут быть отлиты до Rectangle. Есть ли что-то, что я могу добавить к моему классу OrderedDictionary<>, что позволит правильно десериализоваться с помощью JSON.NET? Благодарю.

+0

Какой заказный документ ?, один в 'System.Collections.Specialized'? – Eser

+0

Да. Поскольку я должен использовать 15 символов, я также упоминаю, что я читаю [этот пост] (http://stackoverflow.com/questions/2629027/no-generic-implementation-of-ordereddictionary) и рассматриваю одну из тонких реализаций там, но бойтесь того же десериализационного поведения. –

+0

Возможно, у JSON.NET пока нет поддержки. Вы можете опубликовать этот запрос на https://github.com/JamesNK/Newtonsoft.Json –

ответ

2

Ваша проблема в том, что, хотя вы добавили перечислитель, такие вещи, как индекс, нельзя переопределить. Итак, вы получаете стандартную реализацию нестандартного OrderedDictionary, который не дает вам типизированного результата.

Таким образом, вместо наследования вам нужен фасад, который полностью реализует общий интерфейс.

Вам нужно будет подтвердить свой класс (я только что сделал тестовую работу). Я также обманывал свойства Keys и Values ​​(они не часто используются) и некоторые другие методы ICollection. Просто ленивый :)

  [TestMethod] 
    public void TestJson() 
    { 
     var test = new OrderedDictionary<int, Rectangle>(); 
     test.Add(1, new Rectangle(0, 0, 50, 50)); 
     test.Add(42, new Rectangle(1, 1, 1, 1)); 
     string s = JsonConvert.SerializeObject(test); 

     var deserialized = JsonConvert.DeserializeObject<OrderedDictionary<int, Rectangle>>(s); 

     object someRect = deserialized[1]; 
     Assert.IsNotNull(someRect); 
     Assert.IsTrue(someRect is Rectangle); 
    } 

    public class OrderedDictionary<TKey, TValue> : IDictionary<TKey, TValue> 
    { 
     private readonly OrderedDictionary dic = new OrderedDictionary(); 

     public TValue this[TKey key] { get { return default(TValue); } set { } } 

     public void Add(KeyValuePair<TKey, TValue> item) 
     { 
      dic.Add(item.Key, item.Value); 
     } 
     public void Add(TKey key, TValue value) 
     { 
      dic.Add(key, value); 
     } 

     public void Clear() { dic.Clear(); } 


     public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex) { } 


     public int Count { get { return dic.Count; } } 
     public bool IsReadOnly { get { return false; } } 

     public bool Contains(TKey key) { return dic.Contains(key); } 
     public bool ContainsKey(TKey key) { return dic.Contains(key); } 

     public bool Remove(TKey key) { dic.Remove(key); return true; } 

     public bool TryGetValue(TKey key, out TValue value) { value = default(TValue); return false; } 

     bool ICollection<KeyValuePair<TKey, TValue>>.Contains(KeyValuePair<TKey, TValue> item) 
     { 
      throw new NotImplementedException(); 
     } 
     bool ICollection<KeyValuePair<TKey, TValue>>.Remove(KeyValuePair<TKey, TValue> item) { return false; } 

     public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator() 
     { 
      foreach (DictionaryEntry entry in dic) 
       yield return new KeyValuePair<TKey, TValue>((TKey)entry.Key, (TValue)entry.Value); 
     } 

     IEnumerator IEnumerable.GetEnumerator() 
     { 
      return GetEnumerator(); 
     } 

     private static readonly TKey[] keys = new TKey[0]; 
     private static readonly TValue[] values = new TValue[0]; 

     ICollection<TKey> IDictionary<TKey, TValue>.Keys { get { return keys; } } 
     ICollection<TValue> IDictionary<TKey, TValue>.Values { get { return values; } } 
    } 
+0

К сожалению, 'SortedDictionary' не имеет поведения, которое я хочу. Он сортирует ключи ... Я ищу, чтобы сохранить порядок вставки и удаления. –

+0

Я обновил ответ – AndyPook

Смежные вопросы