使用Newtonsoft.Json序列化时,如何保留作为字典键的枚举类型
枚举作为
Dictionary<Enum, string>键时Json反序列化失败的问题 问题重现
定义枚举:
public enum SomeEnum { One, Two, Three }
执行以下代码会抛出序列化异常:
Dictionary<Enum, string> map = new Dictionary<Enum, string>() { {SomeEnum.One,"1"}, {SomeEnum.Two,"2"}, {SomeEnum.Three,"3"} }; string mapStr = JsonConvert.SerializeObject(map, Formatting.None, new JsonSerializerSettings() { TypeNameAssemblyFormatHandling = TypeNameAssemblyFormatHandling.Full }); var newMap = JsonConvert.DeserializeObject<Dictionary<Enum, string>>(mapStr);
异常信息:
Newtonsoft.Json.JsonSerializationException: 'Could not convert string 'One' to dictionary key type 'System.Enum'. Create a TypeConverter to convert from the string to the key type object. Path 'One', line 1, position 7.'
原因分析
当字典的键使用抽象基类Enum时,Newtonsoft.Json序列化字典键时只会保留枚举的名称(如"One"),不会记录该枚举的具体类型(SomeEnum)。虽然配置了TypeNameAssemblyFormatHandling,但这个设置仅对对象类型生效,无法为字典键附加类型信息。反序列化时,Json.NET无法将纯字符串"One"转换为抽象的Enum类型——因为它不知道要将字符串解析为哪个具体的枚举类。
解决方案
方案1:使用具体枚举类型作为字典键
如果字典只会存储单一类型的枚举,直接将字典的键类型从Enum改为具体的枚举类型(如SomeEnum)即可解决问题,序列化和反序列化都会自动处理:
Dictionary<SomeEnum, string> map = new Dictionary<SomeEnum, string>() { {SomeEnum.One,"1"}, {SomeEnum.Two,"2"}, {SomeEnum.Three,"3"} }; string mapStr = JsonConvert.SerializeObject(map, Formatting.None); var newMap = JsonConvert.DeserializeObject<Dictionary<SomeEnum, string>>(mapStr);
方案2:自定义JsonConverter处理枚举键
如果字典需要支持多种不同类型的枚举,则需要编写自定义转换器,在序列化时同时保存枚举的类型信息和值,反序列化时根据类型信息解析回对应的枚举实例:
首先定义转换器:
public class EnumKeyConverter : JsonConverter { public override bool CanConvert(Type objectType) { return objectType == typeof(Enum); } public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { var enumValue = (Enum)value; // 序列化时拼接类型的程序集限定名和枚举值 writer.WriteValue($"{enumValue.GetType().AssemblyQualifiedName}|{enumValue.ToString()}"); } public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { if (reader.TokenType != JsonToken.String) throw new JsonSerializationException("枚举键格式无效"); var keyStr = (string)reader.Value; var parts = keyStr.Split('|'); if (parts.Length != 2) throw new JsonSerializationException("枚举键格式无效"); var enumType = Type.GetType(parts[0], true); return Enum.Parse(enumType, parts[1]); } }
然后在序列化和反序列化时使用该转换器:
Dictionary<Enum, string> map = new Dictionary<Enum, string>() { {SomeEnum.One,"1"}, {SomeEnum.Two,"2"}, {SomeEnum.Three,"3"} }; // 序列化 string mapStr = JsonConvert.SerializeObject(map, Formatting.None, new JsonSerializerSettings() { Converters = new List<JsonConverter> { new EnumKeyConverter() } }); // 反序列化 var newMap = JsonConvert.DeserializeObject<Dictionary<Enum, string>>(mapStr, new JsonSerializerSettings() { Converters = new List<JsonConverter> { new EnumKeyConverter() } });
内容的提问来源于stack exchange,提问作者user1595443
相关产品推荐
相关产品推荐

