views:

56

answers:

1

It seems impossible to (de-)serialize a generic dictionary using Json.NET out of the box.

class KeyClass
{
    public KeyClass(string p1, string p2) { prop1 = p1; prop2 = p2;}
    public string prop1 { get; set; }
    public string prop2 { get; set; }
}

class ValueClass
{
    public ValueClass(string pa, string pb) { propA = pa; propB = pb;}
    public string propA { get; set; }
    public string propB { get; set; }
}

...

Dictionary<KeyClass, ValueClass> d = new Dictionary<KeyClass, ValueClass>();
d.Add(new KeyClass("k1", "k2"), new ValueClass("v1", "v2"));
d.Add(new KeyClass("k3", "k4"), new ValueClass("v3", "v4"));
string json = JsonConvert.SerializeObject(d);

returns

{"ConsoleApplication1.KeyClass":{"propA":"v1","propB":"v2"},
 "ConsoleApplication1.KeyClass":{"propA":"v3","propB":"v4"}}

where I expected something like:

{{"prop1":"k1","prop2":"k2"}:{"propA":"v1","propB":"v2"},
 {"prop1":"k3","prop2":"k4"}:{"propA":"v3","propB":"v4"}}

So ToString() is called on the key (KeyClass). (an override that generates json doesn't help: escapes the json and just doesn't feel right).

Is it possible to write a CustomCreationConverter for this case?
Is this a hard limitation of json.NET?
If so, do other libraries support this?

+1  A: 

What you're trying to do is not supported in JSON, it has little to do with JSON.NET: a "dictionary" (it's called an object in JSON) must always have string keys. Just look at the JSON specs.

What JSON.NET is doing here is a "right" way to handle a C# dictionary (another is to throw an error).

Note that JavaScript (of which JSON is a very restricted subset) also does not allow your proposed syntax.

One way to serialize a generic dictionary (or non-generic dictionaries with non-string keys) is by serializing it as a list of key-value-pairs, e.g.,

[ { "key": {"prop1":"k1","prop2":"k2"}, "value": {"propA":"v1","propB":"v2"} },
  { "key": {"prop1":"k3","prop2":"k4"}, "value": {"propA":"v3","propB":"v4"} } ]

How to that with JSON.NET is another matter, but if it's possible you can try to expose the dictionary as an IEnumerable<KeyValuePair<X,Y>>.

Ruben