You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 11:28:13