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

如何实现通用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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 20:55:31