如何重构switch语句实现泛型服务的数据获取与IWidget映射?
问题
我有泛型服务接口IService<T>,以及它的实现类ServiceA: IService<A>、ServiceB: IService<B>,分别负责提供类型A和B的数据。现在需要根据指定类型调用对应服务获取数据,判空后映射为IWidget类型。我已经为每种类型编写了映射扩展方法,示例如下:
public static class Mapper { public static IWidget Map(this A data) { return new WidgetA{......}; } public static IWidget Map(this B data) { // 对应B的映射逻辑 } }
现在的问题是,调用GetData后得到的是未知类型,无法直接调用对应的Map方法。我想重构下面的switch代码:
IWidget widget; switch (currentItem.Type) { case "A": { var data = ServiceA.GetData(ProductAlias); if (data == null) { return EmptyContent; } widget = data.Map(); break; }; case "B": { var data = ServiceB.GetData(ProductAlias); if (data == null) { return EmptyContent; } widget = data.Map(); break; }; }
我期望写出类似下面的简洁代码,但object类型无法调用Map方法:
object data = currentItem.Type switch { "A" => ServiceA.GetData(), "B" => ServiceB.GetData(), _ => null }; if (data == null) { return EmptyContent; } var widget = data.Map(); // 无法从Object类型调用Map方法
解决方案
方法1:策略字典封装逻辑
把每种类型的"获取数据+映射"逻辑封装成委托存入字典,通过类型字符串直接索引调用,彻底消除switch判断:
// 静态构造函数中初始化策略字典,避免重复创建 private static readonly Dictionary<string, Func<string, IWidget>> _typeStrategies; static YourCurrentClass() { _typeStrategies = new Dictionary<string, Func<string, IWidget>> { ["A"] = alias => { var data = ServiceA.GetData(alias); return data?.Map() ?? EmptyContent; }, ["B"] = alias => { var data = ServiceB.GetData(alias); return data?.Map() ?? EmptyContent; } }; } // 业务代码中调用 if (_typeStrategies.TryGetValue(currentItem.Type, out var strategy)) { return strategy(ProductAlias); } // 处理未知类型 return EmptyContent;
后续新增类型时,只需要在字典中添加对应的键值对即可,符合开闭原则,代码维护性更高。
方法2:动态类型调用扩展方法
利用dynamic绕过编译时类型检查,让运行时自动匹配对应的Map扩展方法,实现你期望的简洁写法:
dynamic data = currentItem.Type switch { "A" => ServiceA.GetData(ProductAlias), "B" => ServiceB.GetData(ProductAlias), _ => null }; return data?.Map() ?? EmptyContent;
注意:这种方式会失去编译时类型检查,如果后续新增类型但未添加对应的Map方法,会在运行时抛出异常,适合类型变更不频繁的场景。
方法3:泛型接口统一调度(依赖注入场景)
如果项目使用依赖注入,可以通过IServiceProvider获取对应IService<T>实例,结合泛型方法完成统一调度:
// 泛型工具方法 private IWidget GetAndMap<T>(IService<T> service, string alias) { var data = service.GetData(alias); return data?.Map() ?? EmptyContent; } // 业务代码调用 var serviceType = currentItem.Type switch { "A" => typeof(IService<A>), "B" => typeof(IService<B>), _ => null }; if (serviceType == null) { return EmptyContent; } var service = _serviceProvider.GetService(serviceType); var genericMethod = typeof(YourCurrentClass) .GetMethod(nameof(GetAndMap), BindingFlags.NonPublic | BindingFlags.Instance) ?.MakeGenericMethod(serviceType.GetGenericArguments()[0]); return (IWidget)genericMethod?.Invoke(this, new object[] { service, ProductAlias });
这种方式更符合依赖注入的设计思想,适合大型项目中统一管理服务实例的场景。
内容的提问来源于stack exchange,提问作者Kirill_Cyber
相关产品推荐
相关产品推荐

