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

如何使用设计模式消除枚举属性赋值场景下的switch/case冗余代码

优化方案推荐

现有switch分支的写法最大的问题是后续新增PropertyType时需要持续修改分支逻辑,不符合开闭原则,代码会越来越臃肿,下面是两种可落地的优化方案:


方案1:字典映射委托(性能最优,推荐优先使用)

本质是策略模式的轻量化实现,将每个枚举对应的转换、赋值逻辑提前存入静态字典,程序初始化后直接调用,无额外运行时开销。

实现步骤
  1. 首先在当前类中定义静态只读的属性赋值字典,预存所有枚举对应的处理逻辑:
// 字典值为接收Enrichment实例和新值的委托,内置对应属性的赋值、转换逻辑
private static readonly IReadOnlyDictionary<PropertyType, Action<Enrichment, string>> _enrichmentPropertySetters = new Dictionary<PropertyType, Action<Enrichment, string>>
{
    [PropertyType.Color] = (enrichment, newValue) => enrichment.Color = newValue,
    [PropertyType.UsedVehicleModel] = (enrichment, newValue) => enrichment.UsedModel = newValue,
    [PropertyType.UsedVehicleYear] = (enrichment, newValue) => enrichment.UsedYear = newValue,
    [PropertyType.UsedVehicleKm] = (enrichment, newValue) => enrichment.UsedKm = newValue,
    [PropertyType.Payment] = (enrichment, newValue) => enrichment.Payment = Convert.ToInt32(EnumExtension.GetEnumValueFromDescription<PaymentType>(newValue)),
    [PropertyType.ScheduleDate] = (enrichment, newValue) => enrichment.ScheduleDate = DateTime.ParseExact(newValue, "dd/MM/yyyy", CultureInfo.InvariantCulture),
    [PropertyType.SchedulePeriod] = (enrichment, newValue) => enrichment.SchedulePeriod = newValue,
    [PropertyType.SchedulePhone] = (enrichment, newValue) => enrichment.SchedulePhone = newValue,
    [PropertyType.PurchaseType] = (enrichment, newValue) => enrichment.PurchaseType = newValue,
    [PropertyType.HasOptInNextJeep] = (enrichment, newValue) => enrichment.HasOptInNextJeep = Convert.ToBoolean(newValue)
};
  1. 替换原方法中的switch分支逻辑:
private async Task<Enrichment> ParseEnrichmentNewDataAsync(int leadId, string property, string newValue) 
{
    var enrichment = await _context.EnrichmentRepository.GetByLeadIdAsync(leadId);
    if (enrichment == null) 
    {
        enrichment = new Enrichment() 
        {
            LeadId = leadId
        };
    }

    // 替换原switch代码块
    if (Enum.TryParse<PropertyType>(property, out var enumProperty) 
        && _enrichmentPropertySetters.TryGetValue(enumProperty, out var propertySetter))
    {
        propertySetter(enrichment, newValue);
    }
    // 可自行扩展else分支,处理非法属性名、枚举未定义的异常场景
    else
    {
        throw new ArgumentException($"不支持的属性名:{property}");
    }

    return enrichment;
}
方案优势
  • 性能远高于反射实现,无运行时反射开销
  • 符合开闭原则,后续新增属性仅需在字典中新增对应条目即可,无需修改业务逻辑
  • 每个属性的处理逻辑内聚,调试、修改更方便

方案2:自定义特性+反射(适合属性量极大的场景)

如果你的PropertyType枚举数量很多,且大部分属性都是直接赋值不需要特殊转换,可以用这种方案减少重复代码。

实现步骤
  1. 定义自定义属性标记,以及值转换器接口:
// 用来标记枚举对应的Enrichment属性、可选的转换器
[AttributeUsage(AttributeTargets.Field)]
public class EnrichmentPropertyAttribute : Attribute
{
    public string TargetPropertyName { get; }
    public Type? ValueConverterType { get; }

    public EnrichmentPropertyAttribute(string targetPropertyName, Type? valueConverterType = null)
    {
        TargetPropertyName = targetPropertyName;
        ValueConverterType = valueConverterType;
    }
}

// 值转换器接口,特殊转换逻辑实现该接口即可
public interface IValueConverter
{
    object Convert(string inputValue);
}
  1. 为需要特殊转换的场景实现对应转换器:
// 支付类型转换器
public class PaymentConverter : IValueConverter
{
    public object Convert(string inputValue)
    {
        return Convert.ToInt32(EnumExtension.GetEnumValueFromDescription<PaymentType>(inputValue));
    }
}

// 预约日期转换器
public class ScheduleDateConverter : IValueConverter
{
    public object Convert(string inputValue)
    {
        return DateTime.ParseExact(inputValue, "dd/MM/yyyy", CultureInfo.InvariantCulture);
    }
}

// 布尔值转换器
public class BooleanConverter : IValueConverter
{
    public object Convert(string inputValue)
    {
        return Convert.ToBoolean(inputValue);
    }
}
  1. 给PropertyType枚举加特性标记:
public enum PropertyType
{
    [EnrichmentProperty(nameof(Enrichment.Color))]
    Color,
    [EnrichmentProperty(nameof(Enrichment.UsedModel))]
    UsedVehicleModel,
    [EnrichmentProperty(nameof(Enrichment.UsedYear))]
    UsedVehicleYear,
    [EnrichmentProperty(nameof(Enrichment.UsedKm))]
    UsedVehicleKm,
    [EnrichmentProperty(nameof(Enrichment.Payment), typeof(PaymentConverter))]
    Payment,
    [EnrichmentProperty(nameof(Enrichment.ScheduleDate), typeof(ScheduleDateConverter))]
    ScheduleDate,
    [EnrichmentProperty(nameof(Enrichment.SchedulePeriod))]
    SchedulePeriod,
    [EnrichmentProperty(nameof(Enrichment.SchedulePhone))]
    SchedulePhone,
    [EnrichmentProperty(nameof(Enrichment.PurchaseType))]
    PurchaseType,
    [EnrichmentProperty(nameof(Enrichment.HasOptInNextJeep), typeof(BooleanConverter))]
    HasOptInNextJeep
}
  1. 类初始化时构建枚举到属性的映射缓存(避免每次调用都反射),替换赋值逻辑:
// 静态缓存映射关系,仅初始化一次
private static readonly IReadOnlyDictionary<PropertyType, (PropertyInfo TargetProperty, IValueConverter? Converter)> _propertyMap = BuildPropertyMap();

private static IReadOnlyDictionary<PropertyType, (PropertyInfo, IValueConverter?)> BuildPropertyMap()
{
    var map = new Dictionary<PropertyType, (PropertyInfo, IValueConverter?)>();
    var enrichmentType = typeof(Enrichment);
    foreach (PropertyType enumValue in Enum.GetValues(typeof(PropertyType)))
    {
        var member = typeof(PropertyType).GetMember(enumValue.ToString()).First();
        var attr = member.GetCustomAttribute<EnrichmentPropertyAttribute>();
        if (attr == null) continue;

        var targetProp = enrichmentType.GetProperty(attr.TargetPropertyName)!;
        IValueConverter? converter = null;
        if (attr.ValueConverterType != null)
        {
            converter = (IValueConverter)Activator.CreateInstance(attr.ValueConverterType)!;
        }
        map[enumValue] = (targetProp, converter);
    }
    return map;
}

// 原方法中的赋值逻辑替换为:
if (Enum.TryParse<PropertyType>(property, out var enumProperty) 
    && _propertyMap.TryGetValue(enumProperty, out var mapItem))
{
    var valueToSet = mapItem.Converter != null ? mapItem.Converter.Convert(newValue) : newValue;
    mapItem.TargetProperty.SetValue(enrichment, valueToSet);
}
方案优势
  • 新增属性时仅需给枚举加一行特性即可,不需要重复写赋值代码,适合属性数量超过20个的场景
  • 转换逻辑和属性定义耦合,一目了然,便于维护

选型建议

一般业务场景优先选方案1,性能更高、调试更简单,没有反射的心智负担;如果属性数量极多,且90%以上都是直接字符串赋值的场景,可以选方案2减少重复代码。

内容的提问来源于stack exchange,提问作者Matheus Barbosa

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.03 08:39:03