Десериализовать JSON с помощью JSON.NET в наблюдаемый словарь [C #]

Я пытаюсь десериализовать строку JSON в наблюдаемый словарь. Если я использую обычный общий словарь из .NET, он работает хорошо, но если я попытаюсь использовать свой собственный наблюдаемый словарь, я получу исключение:

Данного ключа нет в словаре.

Трассировки стека:

в System.Collections.Generic.Dictionary2.get_Item(TKey key) at ObservableDictionary.MyObservableDictionary2.set_Item (ключ TKey, значение TValue) в C: \ Users \ Jan \ Documents \ Visual Studio 2010 \ Projects \ PokecMessanger - хорошая версия - Copy \ ObservableDictionary \ MyObservableDictionary.cs: строка 163 в Newtonsoft .Json.Utilities.DictionaryWrapper`2.System.Collections.IDictionary.set_Item (ключ объекта, значение объекта) в d: \ Development \ Releases \ Json \ Working \ Src \ Newtonsoft.Json \ Utilities \ DictionaryWrapper.cs: строка 353

Наблюдаемый класс словаря:

public class MyObservableDictionary<TKey, TValue> :
    IDictionary<TKey, TValue>,
    INotifyCollectionChanged,
    INotifyPropertyChanged
{
    private readonly IDictionary<TKey, TValue> _dictionary = new Dictionary<TKey, TValue>();

    #region Implementation of INotifyCollectionChanged

    public event NotifyCollectionChangedEventHandler CollectionChanged;

    #endregion

    #region Implementation of INotifyPropertyChanged

    public event PropertyChangedEventHandler PropertyChanged;

    #endregion

    #region Implementation of IEnumerable

    public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
    {
        return _dictionary.GetEnumerator();
    }

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

    #endregion

    #region Implementation of ICollection<KeyValuePair<TKey,TValue>>

    public void Add(KeyValuePair<TKey, TValue> item)
    {
        _dictionary.Add(item);
        if (CollectionChanged != null)
            CollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add));
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs("Keys"));
            PropertyChanged(this, new PropertyChangedEventArgs("Values"));
        }

    }

    public void Clear()
    {
        int keysCount = _dictionary.Keys.Count;

        _dictionary.Clear();

        if (keysCount == 0) return;

        if (CollectionChanged != null)
        {
            CollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
        }

        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs("Keys"));
            PropertyChanged(this, new PropertyChangedEventArgs("Values"));
        }
    }

    public bool Contains(KeyValuePair<TKey, TValue> item)
    {
        return _dictionary.Contains(item);
    }

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

    public bool Remove(KeyValuePair<TKey, TValue> item)
    {
        bool remove = _dictionary.Remove(item);

        if (!remove) return false;

        if (CollectionChanged != null)
            CollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove));
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs("Keys"));
            PropertyChanged(this, new PropertyChangedEventArgs("Value"));
        }
        return true;
    }

    public int Count
    {
        get { return _dictionary.Count; }
    }

    public bool IsReadOnly
    {
        get { return _dictionary.IsReadOnly; }
    }

    #endregion

    #region Implementation of IDictionary<TKey,TValue>

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

    public void Add(TKey key, TValue value)
    {
        _dictionary.Add(key, value);

        if (CollectionChanged != null)
            CollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add));
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs("Keys"));
            PropertyChanged(this, new PropertyChangedEventArgs("Values"));
        }
    }

    public bool Remove(TKey key)
    {
        bool remove = _dictionary.Remove(key);

        if (!remove) return false;

        if (CollectionChanged != null)
            CollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove));
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs("Keys"));
            PropertyChanged(this, new PropertyChangedEventArgs("Values"));
        }
        return true;
    }

    public bool TryGetValue(TKey key, out TValue value)
    {
        return _dictionary.TryGetValue(key, out value);
    }

    public TValue this[TKey key]
    {
        get { return _dictionary[key]; }
        set
        {
            bool changed = _dictionary[key].Equals(value);

            if (!changed) return;
            _dictionary[key] = value;

            if (CollectionChanged != null)
                CollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace));

            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs("Keys"));
                PropertyChanged(this, new PropertyChangedEventArgs("Values"));
            }
        }
    }

    public ICollection<TKey> Keys
    {
        get { return _dictionary.Keys; }
    }

    public ICollection<TValue> Values
    {
        get { return _dictionary.Values; }
    }

    #endregion
}

Строка JSON выглядит так:

{
  "pepina888": {
    "idUser": 3338870,
    "nick": "pepina888",
    "sefNick": "pepina888",
    "status": 1,
    "photo": "http:\/\/213.215.107.127\/fotky\/333\/88\/s_3338870.jpg?v=9",
    "sex": 2,
    "isFriend": 1
  },
  "yayushka": {
    "idUser": 5281019,
    "nick": "YAYUSHKA",
    "sefNick": "yayushka",
    "status": 1,
    "photo": "http:\/\/213.215.107.125\/fotky\/528\/10\/s_5281019.jpg?v=4",
    "sex": 2,
    "isFriend": 1
  },
  "miska20258": {
    "idUser": 11112713,
    "nick": "miska20258",
    "sefNick": "miska20258",
    "status": 1,
    "photo": "http:\/\/213.215.107.125\/fotky\/1111\/27\/s_11112713.jpg?v=6",
    "sex": 2,
    "isFriend": 1
  },
  ... snip snip ...
}

Код проблемы:

MyObservableDictionary<string, FriendData> friends = new MyObservableDictionary<string, FriendData>();
//problem is here
friends = JsonConvert.DeserializeObject<MyObservableDictionary<string, FriendData>>(jsonString.ToString());

Класс Friend выглядит так:

public class FriendData
{
    public string idUser { get; set; }
    public string nick { get; set; }
    public string sefNick { get; set; }
    public string status { get; set; }
    public string photo { get; set; }
    public string sex { get; set; }
    public string isFriend { get; set; }
    public BitmapImage profilePhoto { get; set; }
    public ImageSource imageSource { get; set; }
    public string blockQuote { get; set; }

    public FriendData(string idUser, string nick, string sefNick, string status, string photo, string sex, string isFriend)
    {
        this.idUser = idUser;
        this.nick = nick;
        this.sefNick = sefNick;
        this.status = status;
        this.photo = photo;
        this.sex = sex;
        this.isFriend = isFriend;
    }
}

Пожалуйста, заранее, не знаю, что может быть не так. Спасибо. При десериализации я использую JSON.NET.

ТО ДЖОНУ СКИТУ: я пробую это

public TValue this[TKey key]
{
    get
    {
        if(TryGetValue(key))
            return _dictionary[key];
    }

    set
    {
        bool changed = _dictionary[key].Equals(value);
        if (!changed) return; 

        _dictionary[key] = value;

        if (CollectionChanged != null)
            CollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace));

        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs("Keys"));
            PropertyChanged(this, new PropertyChangedEventArgs("Values"));
        }
    }
}

person Joe    schedule 07.11.2010    source источник


Ответы (1)


Проблема не в JSON - это ваш словарь. Взгляните на этот код:

public TValue this[TKey key]
{
    get { return _dictionary[key]; }
    set
    {
        bool changed = _dictionary[key].Equals(value);
        ...
    }
}

Как вы ожидаете, что когда-нибудь сможете установить значение в словаре? Индексатор "get" выдаст исключение, если данный ключ отсутствует в словаре.

Вместо этого вам нужно использовать TryGetValue и проверять равенство только в том случае, если ключ действительно присутствовал в первую очередь.

Стоит отметить, что вы должны были найти эту проблему путем модульного тестирования вашего типа словаря, прежде чем вы когда-либо дошли до попытки использовать его в контексте десериализации JSON.

РЕДАКТИРОВАТЬ: исключение возникает в сеттере, потому что вы всегда пытаетесь получить доступ к базовому геттеру словаря. Вам нужно, чтобы это было примерно так:

set
{
    TValue existingValue;
    if (_dictionary.TryGetValue(key, out existingValue))
    {
        // We already have a value for this key. Check whether it's the same.
        if (object.Equals(value, existingValue))
        {
            return;
        }
    }
    // Do the rest of your logic here.
}
person Jon Skeet    schedule 07.11.2010
comment
Я пытаюсь, но не получается. Вы можете привести пример кода? Спасибо - person Joe; 07.11.2010
comment
@Joe: Да, это действительно работает. Пожалуйста, покажите, что вы пробовали - отредактируйте свой вопрос, пытаясь изменить установщик словаря. - person Jon Skeet; 07.11.2010
comment
@Joe: Каким образом вы используете TryGetValue, как я предлагал? Вы по-прежнему используете индексатор словаря в сеттере, поэтому он все равно вызовет исключение. См. Мой ответ отредактировать. - person Jon Skeet; 07.11.2010
comment
(Приносим извинения за резкий тон этого комментария - из-за того, что вы очень заняты, а это вовсе не ваша вина. Надеюсь, что редактирование поможет.) - person Jon Skeet; 07.11.2010