Is there a way to use Json.NET for (de)serialization but continue to use the dictionary serialization conventions of DataContractJsonSerializer
?
In other words, is there a way to read and write JSON in this structure:
{ "MyDict" : [
{ "Key" : "One",
"Value" : 1 },
{ "Key" : "Two",
"Value" : 2 }
] }
Using a class like this (with Json.NET attributes):
public class MyClass
{
public Dictionary<string, int> MyDict { get; set; }
}
It seems like Json.NET's KeyValuePairConverter
might help somehow, but if so, I can't find the correct way to apply it.
I tried attributing MyDict
with [JsonProperty(ItemConverterType = typeof(KeyValuePairConverter))]
, this page even seems to imply that could work, but adding such an attribute results in an ArgumentOutOfRangeException
during serialization.
You're right, the KeyValuePairConverter
doesn't seem to work correctly here. Without digging into the Json.Net source code, I can only speculate as to why. As a workaround, you can make your own custom JsonConverter
to do this translation quite easily:
class MyDictionaryConverter<T> : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return (objectType == typeof(Dictionary<string, T>));
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
JArray array = JArray.Load(reader);
Dictionary<string, T> dict = new Dictionary<string, T>();
foreach (JObject obj in array.Children<JObject>())
{
string key = obj["Key"].ToString();
T val = obj["Value"].ToObject<T>();
dict.Add(key, val);
}
return dict;
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
Dictionary<string, T> dict = (Dictionary<string, T>)value;
JArray array = new JArray();
foreach (KeyValuePair<string, T> kvp in dict)
{
JObject obj = new JObject();
obj.Add("Key", kvp.Key);
obj.Add("Value", JToken.FromObject(kvp.Value));
array.Add(obj);
}
array.WriteTo(writer);
}
}
Apply the converter to the dictionary using a [JsonConverter]
attribute:
public class MyClass
{
[JsonConverter(typeof(MyDictionaryConverter<int>))]
public Dictionary<string, int> MyDict { get; set; }
}
Here is a short demo program showing the converter in action (full round trip):
class Program
{
static void Main(string[] args)
{
MyClass mc = new MyClass { MyDict = new Dictionary<string, int>() };
mc.MyDict.Add("One", 1);
mc.MyDict.Add("Two", 2);
string json = JsonConvert.SerializeObject(mc, Formatting.Indented);
Console.WriteLine(json);
Console.WriteLine();
MyClass mc2 = JsonConvert.DeserializeObject<MyClass>(json);
foreach (KeyValuePair<string, int> kvp in mc2.MyDict)
{
Console.WriteLine(kvp.Key + " == " + kvp.Value);
}
}
}
Output of the above:
{
"MyDict": [
{
"Key": "One",
"Value": 1
},
{
"Key": "Two",
"Value": 2
}
]
}
One == 1
Two == 2
来源:https://stackoverflow.com/questions/24042870/use-json-net-to-deserialize-dictionary-in-the-structure-used-by-datacontractjs