为什么我的序列化JSON最终为
{"Gender":1,"Dictionary":{"Male":100,"Female":200}}
即。为什么enums序列化为它们的值,但是当它们形成时它们是字典的关键字,它们会被转换为它们的键?
如何让它们成为字典中的内容,为什么这不是默认行为?
我希望以下输出
{"Gender":1,"Dictionary":{"0":100,"1":200}}
感谢
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>();
}
}
}
答案 0 :(得分:7)
Gender
枚举用作属性值时序列化为其值的原因,但在用作字典键时序列化为其字符串表示形式如下:
当用作属性值时,JSON.NET序列化程序首先写入属性名称,然后写入属性值。对于您发布的示例,JSON.NET将“Gender”作为属性名称(请注意它写入字符串),而不是尝试解析属性的值。该属性的值是enum类型,JSON.NET处理为Int32
并且它写入枚举的数字表示
序列化字典时,键被写为属性名称,因此JSON.NET序列化程序会写入枚举的字符串表示形式。如果您在字典中切换键和值的类型(Dictionary<int, Gender>
而不是Dictionary<Gender, int>
,则您将验证枚举是否将使用其Int32
表示进行序列化。
要使用您发布的示例实现所需,您需要为Dictionary属性编写自定义JsonConverter
。像这样:
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;
}
}
并在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>();
}
}
调用以下行进行序列化时:
var serializeObject = JsonConvert.SerializeObject(testClass);
您将获得所需的输出:
{"Gender":1,"Dictionary":{"0":100,"1":200}}
答案 1 :(得分:1)
我经常发现自己面临这个问题,所以我做了一个 JsonConverter,它可以处理任何以 Enum 类型为键的字典:
public class DictionaryWithEnumKeyConverter<T, U> : JsonConverter where T : 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;
}
}
注意:这不会处理 Dictionnary<Enum, Dictionnary<Enum, T>