The JSON spec says that property names (keys) in objects must be strings. If you have a dictionary that uses enum values as keys, Json.Net simply calls Convert.ToString()
on those values to get the JSON property names. (This can be seen in the GetPropertyName()
method in the source code, which is called by SerializeDictionary()
.)
It is possible to override this default behavior so that Json.Net will write numeric enum dictionary keys to the JSON (still as strings, of course, in keeping with the spec). This can be done using either a custom ContractResolver
or a custom JsonConverter
. The resolver approach will probably be a bit simpler in this particular case, so I'll show that here. Here is the code you would need:
class CustomResolver : DefaultContractResolver
{
protected override JsonDictionaryContract CreateDictionaryContract(Type objectType)
{
var contract = base.CreateDictionaryContract(objectType);
var keyType = contract.DictionaryKeyType;
if (keyType.BaseType == typeof(Enum))
{
contract.PropertyNameResolver =
propName => ((int)Enum.Parse(keyType, propName)).ToString();
}
return contract;
}
}
To serialize, pass an instance of the custom resolver to the serializer via the settings like this:
JsonSerializerSettings settings = new JsonSerializerSettings();
settings.ContractResolver = new CustomResolver();
string json = JsonConvert.SerializeObject(foo, settings);
Here is a contrived demo to show that it works. You can comment out the line that sets the resolver to toggle the behavior.
class Program
{
static void Main(string[] args)
{
var dict = new Dictionary<Color, string>
{
{ Color.Red, "#FF0000" },
{ Color.Green, "#00FF00" },
{ Color.Blue, "#0000FF" },
{ Color.White, "#FFFFFF" }
};
JsonSerializerSettings settings = new JsonSerializerSettings();
settings.ContractResolver = new CustomResolver();
settings.Formatting = Formatting.Indented;
string json = JsonConvert.SerializeObject(dict, settings);
Console.WriteLine(json);
}
enum Color { Red = 1, Green = 2, Blue = 3, White = 4 }
}
Output:
{
"1": "#FF0000",
"2": "#00FF00",
"3": "#0000FF",
"4": "#FFFFFF"
}