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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 02:27:18