Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Serialize dictionary as array (of key value pairs)

Tags:

c#

json.net

Json.Net typically serializes a Dictionary<k,v> into a collection;

"MyDict": {
  "Apples": {
    "Taste": 1341181398,
    "Title": "Granny Smith",
  },
  "Oranges": {
    "Taste": 9999999999,
    "Title": "Coxes Pippin",
  },
 }

Which is great. And from looking around on SO it seems to be what most people want. However, in this particular case, I want to serialize between my Dictionary<k,v> and the Array format instead;

"MyDict": [
    "k": "Apples",
    "v": {
        "Taste": 1341181398,
        "Title": "Granny Smith",
    }
  },
    "k:": "Oranges",
    "v:": {
        "Taste": 9999999999,
        "Title": "Coxes Pippin",
    }
  },
]

Is there an easy way to do this with my existing field type? Is there an attribute I can annotate for instance?

like image 698
cirrus Avatar asked Oct 05 '12 17:10

cirrus


2 Answers

Another way to accomplish this is to use a custom ContractResolver. That way you do not have to subclass Dictionary<K,V> nor apply a transform each time you serialize, as suggested in other answers.

The following resolver will cause ALL dictionaries to be serialized as an array of objects with "Key" and "Value" properties:

class DictionaryAsArrayResolver : DefaultContractResolver
{
    protected override JsonContract CreateContract(Type objectType)
    {
        if (objectType.GetInterfaces().Any(i => i == typeof(IDictionary) || 
           (i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IDictionary<,>))))
        {
            return base.CreateArrayContract(objectType);
        }

        return base.CreateContract(objectType);
    }
}

To use the resolver, add it to your JsonSerializerSettings, then pass the settings to JsonConvert.SerializeObject() like this:

JsonSerializerSettings settings = new JsonSerializerSettings();
settings.ContractResolver = new DictionaryAsArrayResolver();

string json = JsonConvert.SerializeObject(obj, settings);

Here is a working demo.

like image 73
Brian Rogers Avatar answered Oct 07 '22 23:10

Brian Rogers


Ah, it turns out this is as straightforward as I'd hoped. My Dictionary<k,v> is subclassed already and I found that I can annotate it with [JsonArrayAttribute]. That gives me exactly the format I need;

"MyDict": [
  {
    "Key": "Apples",
    "Value": {
        "Taste": 1341181398,
        "Title": "Granny Smith",
    }
  },
  {
    "Key:": "Oranges",
    "Value:": {
        "Taste": 9999999999,
        "Title": "Coxes Pippin",
    }
  },
]
like image 37
cirrus Avatar answered Oct 07 '22 23:10

cirrus