如何实现通用TypeConverter:逗号分隔字符串转任意自定义枚举数组
通用逗号分隔字符串转任意枚举数组的AutoMapper转换器实现
需求与问题背景
需要实现一个转换器,将逗号分隔的字符串转换为对应自定义枚举的数组,示例如下:
var input = "Value01, Value02"; var output = new CustomEnum[] { CustomEnum.Value01, CustomEnum.Value02 };
当前实现的StringToEnumList转换器仅支持Enum[]类型的属性,无法处理CustomEnum[]这类具体的自定义枚举数组,测试代码如下:
enum CustomEnum { Value01, Value02 } class MyClassSource { public string OkProperty {get; set; } public string FailingProperty {get; set; } } class MyClassTarget { public Enum[] OkProperty {get; set; } public CustomEnum[] FailingProperty {get; set; } }
需要一种无需逐个注册每个自定义枚举的通用转换策略。
解决方案
方案1:泛型转换器+自动条件注册
先实现泛型版本的转换器,针对任意枚举类型:
public class StringToEnumArrayConverter<TEnum> : ITypeConverter<string, TEnum[]> where TEnum : struct, Enum { public TEnum[] Convert(string source, TEnum[] destination, ResolutionContext context) { if (string.IsNullOrWhiteSpace(source)) return Array.Empty<TEnum>(); return source.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries) .Select(s => { if (Enum.TryParse<TEnum>(s.Trim(), out var result)) return result; // 可根据需求调整解析失败的处理逻辑,比如返回默认值或抛出异常 throw new ArgumentException($"无法将值 '{s.Trim()}' 转换为枚举类型 {typeof(TEnum).Name}"); }) .ToArray(); } }
然后在AutoMapper配置中,自动为所有string到枚举数组的映射注册对应转换器:
var cfg = new MapperConfiguration(c => { // 自动识别string到枚举数组的映射场景 c.AddConditionalObjectMapper().Where((sourceType, destType) => sourceType == typeof(string) && destType.IsArray && destType.GetElementType().IsEnum); // 为符合条件的映射绑定泛型转换器 c.ForAllMaps((map, exp) => { if (map.SourceType == typeof(string) && map.DestinationType.IsArray) { var enumElementType = map.DestinationType.GetElementType(); if (enumElementType.IsEnum) { var converterType = typeof(StringToEnumArrayConverter<>).MakeGenericType(enumElementType); exp.ConvertUsing(converterType); } } }); // 注册业务对象映射 c.CreateMap<MyClassSource, MyClassTarget>(); });
方案2:非泛型转换器结合反射
如果不想依赖泛型,可实现一个非泛型转换器,通过反射动态处理目标枚举类型:
public class StringToAnyEnumArrayConverter : ITypeConverter<string, object> { public object Convert(string source, object destination, ResolutionContext context) { if (string.IsNullOrWhiteSpace(source)) return Array.CreateInstance(context.DestinationType.GetElementType(), 0); var enumElementType = context.DestinationType.GetElementType(); if (!enumElementType.IsEnum) throw new InvalidOperationException("目标类型必须是枚举数组"); var parsedValues = source.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries) .Select(s => { if (Enum.TryParse(enumElementType, s.Trim(), out var result)) return result; throw new ArgumentException($"无法将值 '{s.Trim()}' 转换为枚举类型 {enumElementType.Name}"); }) .ToArray(); // 将object数组转换为指定的枚举数组类型 var enumArray = Array.CreateInstance(enumElementType, parsedValues.Length); Array.Copy(parsedValues, enumArray, parsedValues.Length); return enumArray; } }
配置时注册该转换器并指定应用场景:
var cfg = new MapperConfiguration(c => { c.CreateMap<string, object>().ConvertUsing<StringToAnyEnumArrayConverter>(); // 确保所有string到枚举数组的映射使用该转换器 c.ForAllMaps((map, exp) => { if (map.SourceType == typeof(string) && map.DestinationType.IsArray && map.DestinationType.GetElementType().IsEnum) { exp.ConvertUsing<StringToAnyEnumArrayConverter>(); } }); c.CreateMap<MyClassSource, MyClassTarget>(); });
两种方案都无需逐个注册自定义枚举,会自动识别目标属性的枚举数组类型并完成转换。
内容的提问来源于stack exchange,提问作者rolivares
相关产品推荐
相关产品推荐

