IDictionary Support

Apr 6, 2009 at 3:52 AM
Edited Apr 6, 2009 at 3:55 AM
In the release notes for 3.5 Beta 3 it mentions:

New feature - Added support for deserializing to IEnumerable<T>, ICollection<T>, IList<T> and IDictionary<TKey, TValue> members

It appears that whilst the deserialization code for dictionaries is in place, the serialization code isn't. The serialization code (in JsonSerializer.cs) is as follows:

    private IDictionary PopulateDictionary(IWrappedDictionary dictionary, JsonReader reader)
      Type dictionaryType = dictionary.UnderlyingDictionary.GetType();
      Type dictionaryKeyType = ReflectionUtils.GetDictionaryKeyType(dictionaryType);
      Type dictionaryValueType = ReflectionUtils.GetDictionaryValueType(dictionaryType);

      while (reader.Read())
        switch (reader.TokenType)
          case JsonToken.PropertyName:
            object keyValue = EnsureType(reader.Value, dictionaryKeyType);

            dictionary.Add(keyValue, CreateObject(reader, dictionaryValueType, null, null));
          case JsonToken.EndObject:
            return dictionary;
            throw new JsonSerializationException("Unexpected token when deserializing object: " + reader.TokenType);

      throw new JsonSerializationException("Unexpected end when deserializing object.");

Both key and value types are correctly checked and handled. However the serialization code (in JsonSerializer.cs) is as follows:

    private void SerializeDictionary(JsonWriter writer, IDictionary values)

      foreach (DictionaryEntry entry in values)
        SerializeValue(writer, entry.Value, null);


Not only is the key type not checked, but it simply does a ToString on the key (assumes the key is or can be represented as a string). So, the end result is that dictionaries that use any key type other than string, cannot be serialized and deserialized correctly.

Am I missing something here or is it currently a limitation that the key type for a dictionary to be serializable must be a string? I also note that the unit tests do not attempt to test dictionaries that have a non-string key.


Apr 8, 2009 at 4:21 AM
Edited Apr 8, 2009 at 4:21 AM
What else could be done? The property name in JSON has to be a string and the logical way to get the string representation of a .NET type is to use the ToString() method.

I'm sure Dictionary<int, string> should serialize correctly. ToString() on an int value of 1 will return "1". I don't recall whether it will deserialize correctly. When I have time I'll investigate.
Apr 8, 2009 at 9:43 AM
It works. An existing test:

public void NonStringKeyDictionary()
  Dictionary<int, int> values = new Dictionary<int, int>();
  values.Add(-5, 6);
  values.Add(int.MinValue, int.MaxValue);

  string json = JsonConvert.SerializeObject(values);

  Assert.AreEqual(@"{""-5"":6,""-2147483648"":2147483647}", json);

  Dictionary<int, int> newValues = JsonConvert.DeserializeObject<Dictionary<int, int>>(json);

  CollectionAssert.AreEqual(values, newValues);