C#使用JsonStringEnumConverter获取枚举EnumMember自定义字符串值
问题场景
现有JSON数据中的枚举字段以整数形式传输,需要将枚举值转换为EnumMember特性标注的自定义含义字符串展示,当前代码运行后输出枚举成员名Hot_Not,不符合预期,期望输出标注值Not Hot。
当前问题代码:
static void Main(string[] args) { var jsonString = "{\"Summary\":\"40\"}"; var options = new JsonSerializerOptions { Converters = { new JsonStringEnumConverter() } }; WeatherForecastWithEnum? weatherForecast = JsonSerializer.Deserialize<WeatherForecastWithEnum>(jsonString, options)!; Console.WriteLine(weatherForecast.Summary); } public class WeatherForecastWithEnum { public Summary? Summary { get; set; } } public enum Summary { Cold = 30, Cool = 10, Warm = 20, [EnumMember(Value = "Not Hot")] Hot_Not = 40 }
问题原因
两个核心问题导致无法输出预期值:
- 内置
JsonStringEnumConverter默认不识别EnumMember特性,仅支持枚举整数值、枚举原生成员名的映射转换 - 直接通过
Console.WriteLine输出枚举变量时,默认调用枚举的ToString()方法,该方法只会返回枚举成员的原生名称(即Hot_Not),不会主动读取EnumMember特性配置的Value值
解决方案
方法1:编写扩展方法读取EnumMember值(适合代码中直接输出展示场景)
通过反射读取枚举字段上的EnumMember特性值,实现自定义展示。
首先添加枚举扩展方法:
using System.Reflection; using System.Runtime.Serialization; public static class EnumExtensions { public static string GetEnumMemberValue(this Enum value) { var fieldInfo = value.GetType().GetField(value.ToString()); if (fieldInfo == null) return value.ToString(); var enumMemberAttr = fieldInfo.GetCustomAttribute<EnumMemberAttribute>(); return enumMemberAttr?.Value ?? value.ToString(); } }
修改主程序中的输出逻辑,调用扩展方法即可拿到预期值:
Console.WriteLine(weatherForecast.Summary.Value.GetEnumMemberValue()); // 输出:Not Hot
方法2:自定义JsonConverter,支持JSON序列化/反序列化时直接映射EnumMember值
如果需要在JSON处理环节就实现枚举和EnumMember配置值的双向映射,可以自定义支持EnumMember的枚举转换器,替换内置的JsonStringEnumConverter:
using System.Collections.Concurrent; using System.Reflection; using System.Runtime.Serialization; using System.Text.Json; using System.Text.Json.Serialization; public class EnumMemberJsonConverter : JsonConverterFactory { private static readonly ConcurrentDictionary<Type, JsonConverter> _converterCache = new(); public override bool CanConvert(Type typeToConvert) { return typeToConvert.IsEnum || (typeToConvert.IsGenericType && typeToConvert.GetGenericTypeDefinition() == typeof(Nullable<>) && Nullable.GetUnderlyingType(typeToConvert)!.IsEnum); } public override JsonConverter CreateConverter(Type typeToConvert, JsonSerializerOptions options) { return _converterCache.GetOrAdd(typeToConvert, t => { var enumType = t.IsGenericType ? Nullable.GetUnderlyingType(t)! : t; var converterType = typeof(EnumMemberConverterInner<>).MakeGenericType(enumType); return (JsonConverter)Activator.CreateInstance(converterType)!; }); } private class EnumMemberConverterInner<T> : JsonConverter<T> where T : struct, Enum { private static readonly IReadOnlyDictionary<T, string> _enumToStringMap; private static readonly IReadOnlyDictionary<string, T> _stringToEnumMap; static EnumMemberConverterInner() { var enumType = typeof(T); var fields = enumType.GetFields(BindingFlags.Public | BindingFlags.Static); var stringMap = new Dictionary<T, string>(); var enumMap = new Dictionary<string, T>(StringComparer.OrdinalIgnoreCase); foreach (var field in fields) { var enumValue = (T)field.GetValue(null)!; var memberAttr = field.GetCustomAttribute<EnumMemberAttribute>(); var mappedValue = memberAttr?.Value ?? field.Name; stringMap[enumValue] = mappedValue; enumMap[mappedValue] = enumValue; // 支持整数值解析 enumMap[Convert.ToInt32(enumValue).ToString()] = enumValue; } _enumToStringMap = stringMap; _stringToEnumMap = enumMap; } public override T Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.String) { var stringVal = reader.GetString(); if (stringVal != null && _stringToEnumMap.TryGetValue(stringVal, out var result)) { return result; } } // 兼容数值类型读取 if (reader.TokenType == JsonTokenType.Number) { var numVal = reader.GetInt32(); return (T)Enum.ToObject(typeof(T), numVal); } throw new JsonException($"无法转换为枚举{typeof(T).Name}"); } public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options) { writer.WriteStringValue(_enumToStringMap[value]); } } }
使用时替换原有的JsonStringEnumConverter即可:
var options = new JsonSerializerOptions { Converters = { new EnumMemberJsonConverter() } };
该转换器支持:
- 整数形式、字符串形式的枚举值反序列化
EnumMember标注值的序列化输出、反序列化映射- 可空枚举类型处理
注意:JSON转换器只负责JSON序列化/反序列化环节的映射,不会修改枚举本身
ToString()的默认行为,如果需要在代码逻辑中输出自定义值,依然需要调用GetEnumMemberValue扩展方法。
内容的提问来源于stack exchange,提问作者gary_holt
相关产品推荐
相关产品推荐

