如何防止Json.NET将枚举转换为字符串?

3
以下类
public class RequestSections : RequestBase
{
    public RequestSections(Command c, Dictionary<SectionIdentifier, BigInteger> v) : base(c)
    {
        VERSIONS = v;
    }

    public Dictionary<SectionIdentifier, BigInteger> VERSIONS { get; set; }
}

使用JSON.NET将其序列化为JSON,生成以下JSON输出:
{
  "VERSIONS": {
    "Photos": 901,
    "Music": 902
  },
  "CMD": 43
}

问题在于SectionIdentifier是一个enum类型,但JSON.NET将它们转换为字符串。
public enum SectionIdentifier
{
    Photos = 1000,
    Music
}

我该如何防止JSON.NET将整数枚举值转换为字符串?我只想看到它们的整数表示。
顺便说一句,位于RequestBase类中的CMD也是枚举类型,但幸运的是它没有被转换为字符串。

2
你可以随时编写自己的 JsonConverter - Jeroen Vannevel
我希望能够理解为什么有时它会转换为字符串,有时不会,因为我在某个地方读到JSON.NET默认将枚举转换为整数。 - Pablo
正如@JeroenVannevel所提到的,您可以编写自己的JsonConverter这篇博客文章解释了您可能会如何做到这一点。 - fourpastmidnight
你正在将枚举用作字典的键而不是值。这就是为什么它们被转换为字符串的原因。 - Dejan
啊,所以 JSON 规范本身防止我使用非字符串键,对吧? - Pablo
你可以将数字作为键,但将其转换为字符串(如此处所述:https://dev59.com/Lmoy5IYBdhLWcg3wHqiB)。 - Dejan
1个回答

15

JSON规范 指出对象中的属性名(键)必须是字符串。如果您有一个使用枚举值作为键的字典,Json.Net会简单地调用Convert.ToString()方法来获取JSON属性名。(这可以在源代码中的 GetPropertyName() 方法中看到,该方法由 SerializeDictionary() 调用。)

可以重写此默认行为,以使 Json.Net 将数字枚举字典键写入 JSON(当然还是作为字符串,符合规范)。 这可以使用自定义的 ContractResolver 或自定义的 JsonConverter 来实现。 在这种特定情况下,使用解析器方法可能会更简单,因此我将在此处展示该方法。以下是所需的代码:

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;
    }
}

要进行序列化,可以通过设置将自定义解析器的实例传递给序列化程序,例如:

JsonSerializerSettings settings = new JsonSerializerSettings();
settings.ContractResolver = new CustomResolver();

string json = JsonConvert.SerializeObject(foo, settings);

这是一个人为制造的演示,以展示它的工作原理。您可以注释掉设置解析器以切换行为的那一行。

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 }
}

输出:

{
  "1": "#FF0000",
  "2": "#00FF00",
  "3": "#0000FF",
  "4": "#FFFFFF"
}

1
作为参考,现在您可能希望设置DictionaryKeyResolver而不是PropertyNameResolver。 - Michael Tontchev

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接