JSON.Net默认情况下将枚举序列化为字典中的字符串 - 如何将其序列化为int?

And*_*ock 8 c# json.net

为什么我的序列化JSON最终为

{"Gender":1,"Dictionary":{"Male":100,"Female":200}}
Run Code Online (Sandbox Code Playgroud)

即为什么enums序列化为它们的值,但是当它们形成时它们是字典的关键字,它们被转换为它们的键?

如何使它们成为字典中的整数,为什么这不是默认行为?

我希望得到以下输出

{"Gender":1,"Dictionary":{"0":100,"1":200}}
Run Code Online (Sandbox Code Playgroud)

谢谢

    public void foo()
    {
        var testClass = new TestClass();
        testClass.Gender = Gender.Female;
        testClass.Dictionary.Add(Gender.Male, 100);
        testClass.Dictionary.Add(Gender.Female, 200);

        var serializeObject = JsonConvert.SerializeObject(testClass);

        // serializeObject == {"Gender":1,"Dictionary":{"Male":100,"Female":200}}
    }

    public enum Gender
    {
        Male = 0,
        Female = 1
    }

    public class TestClass
    {
        public Gender Gender { get; set; }
        public IDictionary<Gender, int> Dictionary { get; set; }

        public TestClass()
        {
            this.Dictionary = new Dictionary<Gender, int>();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

Ili*_*mov 7

Gender枚举在用作属性值时序列化为其值的原因,但在用作字典键时序列化为其字符串表示形式如下:

  • 当用作属性值时,JSON.NET序列化程序首先写入属性名称,然后写入属性值.对于您发布的示例,JSON.NET将"Gender"作为属性名称(请注意它写入字符串),而不是尝试解析属性的值.该属性的值是jSON.NET处理的类型enum,Int32它写入枚举的数字表示

  • 序列化字典时,键被写为属性名称,因此JSON.NET序列化程序会写入枚举的字符串表示形式.如果您在字典中切换键和值的类型(Dictionary<int, Gender>而不是Dictionary<Gender, int>,您将验证枚举将使用其Int32表示序列化.

要使用您发布的示例实现所需,您需要JsonConverter为Dictionary属性编写自定义.像这样的东西:

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

并在以下地方装饰物业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>();
    }
}
Run Code Online (Sandbox Code Playgroud)

调用以下行进行序列化时:

var serializeObject = JsonConvert.SerializeObject(testClass);
Run Code Online (Sandbox Code Playgroud)

你会得到所需的输出:

{"Gender":1,"Dictionary":{"0":100,"1":200}}
Run Code Online (Sandbox Code Playgroud)


deK*_*joo 6

我经常发现自己面临这个问题,所以我做了一个 JsonConverter ,它可以处理任何类型的字典,以 Enum 类型作为键:

public class DictionaryWithEnumKeyConverter<T, U> : JsonConverter where T : System.Enum
{
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        var dictionary = (Dictionary<T, U>)value;

        writer.WriteStartObject();

        foreach (KeyValuePair<T, U> pair in dictionary)
        {
            writer.WritePropertyName(Convert.ToInt32(pair.Key).ToString());
            serializer.Serialize(writer, pair.Value);
        }

        writer.WriteEndObject();
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        var result = new Dictionary<T, U>();
        var jObject = JObject.Load(reader);

        foreach (var x in jObject)
        {
            T key = (T) (object) int.Parse(x.Key); // A bit of boxing here but hey
            U value = (U) x.Value.ToObject(typeof(U));
            result.Add(key, value);
        }

        return result;
    }

    public override bool CanConvert(Type objectType)
    {
        return typeof(IDictionary<T, U>) == objectType;
    }
}
Run Code Online (Sandbox Code Playgroud)

注意:这不会处理Dictionnary<Enum, Dictionnary<Enum, T>