.Net Core 3中是否存在StringEnumConverter的替代方案?
在.NET Core 3+中扩展System.Text.Json的枚举字符串转换(无需重写完整转换器)
我完全懂你的困扰——之前用Newtonsoft.Json的时候,继承StringEnumConverter就能轻松给枚举字符串绑定加验证、自定义错误信息,结果到了.NET Core 3及以后,System.Text.Json的JsonStringEnumConverter直接被标成sealed了,想继承扩展门都没有,又不想退回到Newtonsoft,也不想从零写个完整的枚举转换器?别慌,这里有个巧妙的办法,不用重复造轮子,直接复用微软内置转换器的逻辑,同时加上你要的自定义验证。
核心思路:用JsonConverterFactory包装内置转换器
JsonConverterFactory是System.Text.Json里用来批量创建转换器的接口,我们可以用它来“包装”现有的JsonStringEnumConverter,在它的序列化/反序列化流程前后插入自定义逻辑——比如验证枚举值是否合法,或者抛出带自定义信息的异常。
实现代码示例
下面这个工厂类会帮你封装内置的枚举转换器,同时添加自定义验证:
public class ValidatingJsonStringEnumConverterFactory : JsonConverterFactory { // 复用内置的JsonStringEnumConverter处理基础转换 private readonly JsonStringEnumConverter _innerConverter; public ValidatingJsonStringEnumConverterFactory(JsonNamingPolicy namingPolicy = null, bool allowIntegerValues = true) { _innerConverter = new JsonStringEnumConverter(namingPolicy, allowIntegerValues); } // 只处理枚举类型,和内置转换器保持一致 public override bool CanConvert(Type typeToConvert) { return _innerConverter.CanConvert(typeToConvert); } public override JsonConverter CreateConverter(Type typeToConvert, JsonSerializerOptions options) { // 获取内置转换器的实例 var innerConverter = (JsonConverter)_innerConverter.CreateConverter(typeToConvert, options); // 返回包装后的转换器,插入自定义逻辑 return new ValidatingEnumConverterWrapper(typeToConvert, innerConverter); } // 内部包装类,负责插入自定义逻辑 private class ValidatingEnumConverterWrapper : JsonConverter { private readonly Type _enumType; private readonly JsonConverter _innerConverter; public ValidatingEnumConverterWrapper(Type enumType, JsonConverter innerConverter) { _enumType = enumType; _innerConverter = innerConverter; } public override bool CanConvert(Type typeToConvert) { return _innerConverter.CanConvert(typeToConvert); } public override object Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { // 先让内置转换器完成字符串到枚举的基础转换 var enumValue = _innerConverter.Read(ref reader, typeToConvert, options); // 这里添加你的自定义验证逻辑,比如检查枚举值是否被定义 if (!Enum.IsDefined(_enumType, enumValue)) { throw new JsonException($"无效的枚举值:{enumValue},请使用{_enumType.Name}枚举中定义的有效值"); } return enumValue; } public override void Write(Utf8JsonWriter writer, object value, JsonSerializerOptions options) { // 序列化逻辑直接复用内置转换器,也可以在这里加自定义处理(比如格式化枚举值) _innerConverter.Write(writer, value, options); } } }
如何使用
只需要把这个工厂添加到JsonSerializerOptions的转换器集合里就可以了,完全兼容内置转换器的所有配置(比如驼峰命名、允许整数值):
var jsonOptions = new JsonSerializerOptions { // 添加我们的自定义工厂,同时指定命名策略 Converters.Add(new ValidatingJsonStringEnumConverterFactory(JsonNamingPolicy.CamelCase)) }; // 测试反序列化:如果传入无效的枚举字符串,就会抛出我们自定义的错误信息 try { var result = JsonSerializer.Deserialize<OrderStatus>("\"InvalidStatus\"", jsonOptions); } catch (JsonException ex) { Console.WriteLine(ex.Message); // 输出:无效的枚举值:InvalidStatus,请使用OrderStatus枚举中定义的有效值 }
进阶玩法:针对特定枚举类型定制验证
如果需要给不同的枚举类型加不同的验证逻辑,只需要在CreateConverter方法里判断typeToConvert,返回不同的包装器即可。比如:
public override JsonConverter CreateConverter(Type typeToConvert, JsonSerializerOptions options) { var innerConverter = (JsonConverter)_innerConverter.CreateConverter(typeToConvert, options); if (typeToConvert == typeof(OrderStatus)) { return new OrderStatusValidatingWrapper(typeToConvert, innerConverter); } else if (typeToConvert == typeof(UserRole)) { return new UserRoleValidatingWrapper(typeToConvert, innerConverter); } return new ValidatingEnumConverterWrapper(typeToConvert, innerConverter); }
这样就能针对不同枚举类型实现差异化的验证逻辑,同时依然复用内置转换器的核心功能。
内容的提问来源于stack exchange,提问作者Ilya Chernomordik
相关产品推荐
相关产品推荐

