The reason why Gender
enum is serialized to its value when used as property value, but it is serialized to its string representation when used as dictionary key is the following:
When used as property value JSON.NET serializer first writes the property name and after that the property value. For the example you posted, JSON.NET will write "Gender" as property name (notice that it writes a string), than will try to resolve the value of the property. The value of the property is of type enum which JSON.NET handles as Int32
and it writes the number representation of the enum
When serializing the dictionary, the keys are written as property names, so the JSON.NET serializer writes the string representation of the enum. If you switch the types of the keys and values in the dictionary (Dictionary<int, Gender>
instead of Dictionary<Gender, int>
, you'll verify that the enum will be serialized with its Int32
representation.
To achieve what you want with the example you posted, you'll need to write custom JsonConverter
for the Dictionary property. Something like this:
public class DictionaryConverter : JsonConverter
{
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
var dictionary = (Dictionary<Gender, int>) value;
writer.WriteStartObject();
foreach (KeyValuePair<Gender, int> pair in dictionary)
{
writer.WritePropertyName(((int)pair.Key).ToString());
writer.WriteValue(pair.Value);
}
writer.WriteEndObject();
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
var jObject = JObject.Load(reader);
var maleValue = int.Parse(jObject[((int) Gender.Male).ToString()].ToString());
var femaleValue = int.Parse(jObject[((int)Gender.Female).ToString()].ToString());
(existingValue as Dictionary<Gender, int>).Add(Gender.Male, maleValue);
(existingValue as Dictionary<Gender, int>).Add(Gender.Female, femaleValue);
return existingValue;
}
public override bool CanConvert(Type objectType)
{
return typeof (IDictionary<Gender, int>) == objectType;
}
}
and decorate the property in the TestClass
:
public class TestClass
{
public Gender Gender { get; set; }
[JsonConverter(typeof(DictionaryConverter))]
public IDictionary<Gender, int> Dictionary { get; set; }
public TestClass()
{
this.Dictionary = new Dictionary<Gender, int>();
}
}
When calling the following line for serialization:
var serializeObject = JsonConvert.SerializeObject(testClass);
you'll get the desired output:
{"Gender":1,"Dictionary":{"0":100,"1":200}}