Ryan Elkins
Ryan Elkins

Reputation: 5797

Deserializing a List of Objects that contain a Dictionary

I've seen a lot of examples that seem to indicate that what I'm doing should work, but for whatever reason, it doesn't. I'm trying to deserialize a collection of objects, one of the properties of which is a Dictionary, like so:

class Program
{
    static void Main(string[] args)
    {
        var json = "{\"Collection\":[{\"ID\":\"1243\",\"Dictionary\":[{\"Key\":\"color\", \"Value\":\"red\"},{\"Key\":\"size\",\"Value\":\"large\"}]},{\"ID\":\"1243\",\"Dictionary\":[{\"Key\":\"color\", \"Value\":\"blue\"},{\"Key\":\"size\",\"Value\":\"small\"}]}]}";
        //var json = "[{\"ID\":\"1243\",\"Dictionary\":[{\"Key\":\"color\", \"Value\":\"red\"},{\"Key\":\"size\",\"Value\":\"large\"}]},{\"ID\":\"1243\",\"Dictionary\":[{\"Key\":\"color\", \"Value\":\"blue\"},{\"Key\":\"size\",\"Value\":\"small\"}]}]";
        List<MyObject> myObjects = new JavaScriptSerializer().Deserialize<List<MyObject>>(json);
    }
}

[DataContract]
public class MyObject
{
    [DataMember]
    public string ID { get; set; }

    [DataMember]
    public Dictionary<string, string> Dictionary { get; set; }
}

The first json string encapsulates the whole thing in an object - if I run that one it runs fine but myObjects is just an empty list. If I run the second string (without it being wrapped) I get the following error:

Type 'System.Collections.Generic.Dictionary`2[[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]' is not supported for deserialization of an array.

From the research I've done this seems like it should be pretty straight forward - anyone have any ideas as to which JSON format I should be using and what is going wrong? The JSON deserializes just fine if I just do one object instead of an array of objects.

Upvotes: 6

Views: 10191

Answers (3)

Murray Foxcroft
Murray Foxcroft

Reputation: 13755

Obviously a little late to the part for the OP :) but I hit similar today and used the following to solve it:

        //var json = "[{'firstName':'John', 'lastName':'Doe'},{'firstName':'Anna', 'lastName':'Smith'},{'firstName':'Peter','lastName': 'Jones'} ]";
        //var json = "{ 'glossary': { 'title': 'example glossary','GlossDiv': { 'title': 'S','GlossList': { 'GlossEntry': { 'ID': 'SGML','SortAs': 'SGML','GlossTerm': 'Standard Generalized Markup Language','Acronym': 'SGML','Abbrev': 'ISO 8879:1986','GlossDef': { 'para': 'A meta-markup language, used to create markup languages such as DocBook.','GlossSeeAlso': ['GML', 'XML'] },'GlossSee': 'markup' } } } } }";
        var json = "{ 'A': 'A0' , 'B' : { 'B2' : 'B2 - Val', 'B3' : [{'B30' : 'B30 - Val1' ,'B31' : 'B31 - Val1'}]}, 'C': ['C0', 'C1']}";
        var jss = new JavaScriptSerializer();

        try
        {
            // Deal with an Object root
            var dict = jss.Deserialize<Dictionary<string, object>>(json);
            //<do stuff>
        }
        catch (InvalidOperationException ioX)
        {
            // Deal with an Array Root
            var dictionaries = jss.Deserialize<Dictionary<string, object>[]>(json);
            foreach (var dict in dictionaries)
            {
                //<do stuff for each dictionary>
            }
        }

Upvotes: 1

Praveen
Praveen

Reputation: 100

Yeah true, the deserializers dont deserialize the dictornary object especailly if you have any complex types and dates. The solution for that is use Newtonsoft.Json use Jobject to deserialize you can take this as an example and try.. In your case you can take this to var or Jobject

    JArray resources=(JArray)JsonConvert.DeserializeObject(objJson);
                     itemStores = resources.Select(resource => new Resource`enter code here`
                     {
                         SpaceUsed = long.Parse(resource["indexDiskMB"].ToString()),
                         ItemId =resource["id"].ToString(),
                         CountItems =Int32.Parse(resource["numItems"].ToString()),
                         ItemType=resource["type"].ToString()

                     }).ToList();

Upvotes: 4

Joe Enos
Joe Enos

Reputation: 40403

Looks like Dictionary<string, string> is not serializable the way you'd expect. I tried List<KeyValuePair<string, string>> instead, and that doesn't seem to work either.

Only thing I can think of is some ugly stuff that will convert your JSON into a custom type, and then convert it into a dictionary. So using your 2nd JSON example exactly as-is, you can do something like:

// Inside of MyObject class
[DataMember]
public Kvp<string, string>[] Dictionary { get; set; }

public Dictionary<string, string> GetDictionary()
{
    return Dictionary.ToDictionary(x => x.Key, x => x.Value);
}

//////////////////

public class Kvp<T1, T2>
{
    public T1 Key { get; set; }
    public T2 Value { get; set; }
}

Dictionary<string, string> myDictionary = myObjects[0].GetDictionary();

I'm sure there's a much better way, but this should at least work.

Upvotes: 1

Related Questions