The following class
public class RequestSections : RequestBase
{
public RequestSections(Command c, Dictionary<SectionIdentifier, BigInteger> v) : base(c)
{
VERSIONS = v;
}
public Dictionary<SectionIdentifier, BigInteger> VERSIONS { get; set; }
}
is serialized to JSON using JSON.NET and producing the following JSON output:
{
"VERSIONS": {
"Photos": 901,
"Music": 902
},
"CMD": 43
}
The problem is that SectionIdentifier
is enum
but JSON.NET converts them to string.
public enum SectionIdentifier
{
Photos = 1000,
Music
}
How can I prevent JSON.NET converting integer enum
values to string? I would like to see their integer representations only.
By the way, CMD
which is residing in RequestBase
class is also enum
type, but somehow luckily it is not converted to string.
1 Answer 1
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"
}
-
1For reference, nowadays you probably want to set DictionaryKeyResolver rather than PropertyNameResolver.Michael Tontchev– Michael Tontchev2019年01月30日 18:27:29 +00:00Commented Jan 30, 2019 at 18:27
JsonConverter
.JsonConverter
. Here's a blog post that explains how you might do that.