为什么我的序列化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)
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)
我经常发现自己面临这个问题,所以我做了一个 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>