2

How would you serialize and deserialize a dictionary whose keys are integers to JSON, using a JavaScriptSerializer and a custom JavaScriptConverter?

For those who don't know, the JavaScripSerializer cannot do this out of the box.

Please note that I'm not interested in a solution that requires converting the dictionary prior to serialization or that uses another serializer (if you are, you may see this post).

UPDATE: to remove any ambiguity, I have no problem with the fact the key is generated as a string in JSON (so 1 will become "1").

Community
  • 1
  • 1
Gyum Fox
  • 3,287
  • 2
  • 41
  • 71
  • So, you want JSON name to be not a `string` value but `int`. Is it consistent with JSON object name/value pair format at all? – Andrew Orlov Aug 14 '15 at 10:17
  • @AndrewOrlov yes that's what I want. I don't see how it's violating JSON format (you may use any string key; "1" would be a valid key). The most import thing for me is that javaScriptSerializer.Deserialize(javaScriptSerializer.Serialize(dictionary)) works smoothly. – Gyum Fox Aug 14 '15 at 10:19
  • Why the downvotes, please add a comment so we can refine the question. No need for downvote if you don't have the answer. – Gyum Fox Aug 14 '15 at 11:48
  • `JavaScriptSerializer.Deserialize` method works in accordance with the requirements of JSON format. With this requirements your key type should be only `string` and method throws special argument exception for another situations - "Type is not supported for serialization/deserialization of a dictionary, keys must be strings or objects". So, yes, it is kind of violation. And why you aren't want to deserialize JSON to `IDictionary` with next converting `string` key to `int`? – Andrew Orlov Aug 14 '15 at 11:58
  • Then feel free to open this post http://stackoverflow.com/questions/5597349/how-do-i-convert-a-dictionary-to-a-json-string-in-c and downvote all the questions and answers. I'm trying to fix an asmx service, and it happens that some class used in the webmethods contain this type. I don't want the asmx to dictate the implementation of the backend classes. This would break over and over. – Gyum Fox Aug 14 '15 at 12:06

1 Answers1

6
/// <summary>
/// Implements JavaScript Serialization and Deserialization for instances of the Dictionary&lt;int, object&gt; type.
/// </summary>
public class IntDictionaryConverter : JavaScriptConverter
{
    /// <summary>
    /// Converts the provided dictionary into a Dictionary&lt;int, object&gt; object.
    /// </summary>
    /// <param name="dictionary">An IDictionary instance of property data stored as name/value pairs.</param>
    /// <param name="type">The type of the resulting object.</param>
    /// <param name="serializer">The JavaScriptSerializer instance.</param>
    /// <returns>The deserialized object.</returns>
    public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer)
    {
        // Validate arguments
        if (dictionary == null) throw new ArgumentNullException("dictionary");
        if (serializer == null) throw new ArgumentNullException("serializer");

        Dictionary<int, object> deserializedDictionary = new Dictionary<int, object>();
        foreach (KeyValuePair<string, object> entry in dictionary)
        {
            int intKey = 0;
            if (!int.TryParse(entry.Key, out intKey))
                throw new InvalidOperationException("Cannot deserialize the dictionary because of invalid number string");

            deserializedDictionary.Add(intKey, entry.Value);
        }

        return deserializedDictionary;
    }

    /// <summary>
    /// Builds a dictionary of name/value pairs.
    /// </summary>
    /// <param name="obj">The object to serialize.</param>
    /// <param name="serializer">The object that is responsible for the serialization.</param>
    /// <returns>An object that contains key/value pairs that represent the object’s data.</returns>
    public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
    {
        // Validate arguments
        if (obj == null) throw new ArgumentNullException("obj");
        if (serializer == null) throw new ArgumentNullException("serializer");

        // Get the dictionary to convert
        Dictionary<int, object> dictionary = (Dictionary<int, object>)obj;

        // Build the converted dictionary
        Dictionary<string, object> convertedDictionary = new Dictionary<string, object>();

        foreach (KeyValuePair<int, object> entry in dictionary)
            convertedDictionary.Add(entry.Key.ToString(), entry.Value);

        return convertedDictionary;
    }

    /// <summary>
    /// Gets a collection of the supported types.
    /// </summary>
    public override System.Collections.Generic.IEnumerable<Type> SupportedTypes
    {
        get
        {
            return new Type[]
            {
                typeof(Dictionary<int, object>)
            };
        }
    }
}
Gh61
  • 9,222
  • 4
  • 28
  • 39