C#如何实现支持预定义手动映射规则的通用泛型Mapper?
问题场景
多个类包含重复的对象映射逻辑,为遵循DRY原则避免冗余代码,计划创建抽象基类封装通用逻辑,基类中包含如下泛型实体获取方法:
public TEntity GetEntity(Result<TServiceClientEntity> res) { entity = MappingProfiles.TryMap(res.Value); // 此处编写结果处理的通用逻辑 return entity; }
用到的泛型Result类定义如下:
public class Result<T> { public T Value{ get; set; } // 其余业务属性定义 }
当前卡在MappingProfiles的泛型TryMap实现上,现有写法无法根据传入的实际类型自动匹配对应的手写Map方法:
public static class MappingProfiles { public static T2 TryMap<T,T2>(T t) { return (T2)Map((Real_T_type)t); // 硬编码实际类型的写法无法适配泛型场景 } public static ExampleTo Map(ExampleFrom from) { return new ExampleTo { exapleValue = from.exapleValue }; } }
补充要求:
TryMap泛型方法必须调用预先定义好的手动Map方法完成映射,不能用自动映射类库替代手写逻辑。
实现方案
用预注册映射委托的方式实现,无额外反射开销,可完全复用已写好的手动Map方法,具体实现如下:
- 在
MappingProfiles中新增静态字典做映射缓存,键为「源类型+目标类型」的元组,值为对应的映射委托 - 在静态构造函数中把所有手写的
Map方法注册到缓存字典中 TryMap方法运行时根据传入的泛型类型从缓存取对应委托执行即可,找不到匹配映射时可按业务需求抛出明确异常或返回默认值
完整可运行代码:
public static class MappingProfiles { // 映射委托缓存,键格式为(源类型, 目标类型) private static readonly Dictionary<(Type From, Type To), Delegate> _mapperCache = new(); // 类首次加载时注册所有手写映射方法 static MappingProfiles() { // 注册已写好的ExampleFrom -> ExampleTo映射 Register<ExampleFrom, ExampleTo>(Map); // 后续新增手写Map方法,在此处追加一行Register调用即可 } // 映射注册辅助方法 public static void Register<TFrom, TTo>(Func<TFrom, TTo> mapFunc) { _mapperCache[(typeof(TFrom), typeof(TTo))] = mapFunc; } public static T2 TryMap<T, T2>(T source) { var typeKey = (typeof(T), typeof(T2)); if (_mapperCache.TryGetValue(typeKey, out var mapDelegate)) { return ((Func<T, T2>)mapDelegate)(source); } // 未找到映射的处理逻辑,可按需调整为返回默认值、记录日志等 throw new InvalidOperationException($"未注册从{typeof(T).Name}到{typeof(T2).Name}的映射规则"); } // 原有手写Map方法无需任何修改 public static ExampleTo Map(ExampleFrom from) { return new ExampleTo { exapleValue = from.exapleValue }; } }
方案说明
- 所有映射逻辑完全复用你预先写好的手动
Map方法,没有自动生成的映射逻辑,完全符合要求 - 注册逻辑仅在类首次加载时执行一次,后续调用直接取委托执行,性能和直接调用手写方法几乎无差异
- 该实现可以直接配合你之前写的抽象基类泛型方法使用,不需要修改基类的任何逻辑,通用结果处理代码可以正常复用
- 如果不想每次新增映射都手动写注册代码,也可以加一段启动时反射扫描的逻辑,自动识别
MappingProfiles类中命名为Map、入参和返回值符合规则的方法自动注册,手动注册的方式可控性更高,可根据项目规模选择。
内容的提问来源于stack exchange,提问作者Yoro
相关产品推荐
相关产品推荐

