找回密码
 立即注册
首页 业界区 业界 如何使用PocoEmit.Mapper替代AutoMapper

如何使用PocoEmit.Mapper替代AutoMapper

煅圆吧 2025-9-28 18:38:45
PocoEmit使用比较简单对于大部分转化是不需要手动配置
可以替代AutoMapper的大部分工作,实现精简代码,提高性能
一、获取Mapper实例

1. 获取Mapper默认实例

Default是一个静态延迟初始化的默认实例
  1. IMapper mapper =  PocoEmit.Mapper.Default;
复制代码
2. 构造Mapper新实例



  • 除了测试,不建议每次转化调用Create
  • Create的实例建议定义为静态字段或属性
  • 或者注入IOC容器内重复使用
  1. IMapper mapper =  PocoEmit.Mapper.Create();
复制代码
二、简单类型转化无需配置

什么样的类型转化对PocoEmit来说是简单的呢
1. 基础类型、枚举互转

基础类型、枚举互转无需配置
  1. int intValue =  PocoEmit.Mapper.Default.Convert<string, long>("123");
  2. long longValue =  PocoEmit.Mapper.Default.Convert<int, long>(123);
  3. strting stringValue =  PocoEmit.Mapper.Default.Convert<int, string>(123);
复制代码
  1. public enum MyColor
  2. {
  3.     None = 0,
  4.     Red = 1,
  5.     Green = 2,
  6.     Blue = 3,
  7. }
  8. ConsoleColor color = ConsoleColor.DarkBlue;
  9. // Red
  10. MyColor redColor = PocoEmit.Mapper.Default.Convert<ConsoleColor, MyColor>(ConsoleColor.Red);
  11. string colorName =  PocoEmit.Mapper.Default.Convert<ConsoleColor, string>(ConsoleColor.Red);
  12. // 1
  13. long colorValue =  PocoEmit.Mapper.Default.Convert<MyColor, long>(MyColor.Red);
  14. / None
  15. MyColor noneColor = PocoEmit.Mapper.Default.Convert<ConsoleColor, MyColor>(ConsoleColor.DarkBlue);
复制代码
2. 可空类型转化

可空类型转化无需配置
  1. int intValue =  PocoEmit.Mapper.Default.Convert<string?, long>("123");
  2. long? longValue =  PocoEmit.Mapper.Default.Convert<int, long?>(123);
  3. strting stringValue =  PocoEmit.Mapper.Default.Convert<int?, string>(123);
  4. User user = PocoEmit.Mapper.Default.Convert<User?, User>(null);
复制代码
3. 构造函数和属性互转

构造函数和属性互转无需配置
  1. class MyId(int id)
  2. {
  3.     public int Id { get; } = id;
  4. }
  5. class MyId2(int? id)
  6. {
  7.     public int? Id { get; } = id;
  8. }
复制代码
3.1 构造函数转化
  1. var myId = PocoEmit.Mapper.Default.Convert<int, MyId>(1);
  2. var myId2 = PocoEmit.Mapper.Default.Convert<int?, MyId2>(2);
  3. var myId3 = PocoEmit.Mapper.Default.Convert<int?, MyId>(3);
  4. var myId4 = PocoEmit.Mapper.Default.Convert<int, MyId2>(4);
复制代码
3.2 属性转化
  1. var id = PocoEmit.Mapper.Default.Convert<MyId, int>(new MyId(1));
  2. var id2 = PocoEmit.Mapper.Default.Convert<MyId2, int?>(new MyId2(2));
  3. var id3 = PocoEmit.Mapper.Default.Convert<MyId, int?>(new MyId(3));
  4. var id4 = PocoEmit.Mapper.Default.Convert<MyId2, int>(new MyId2(4));
复制代码
4. 复合类型同名属性互转

复合类型同名属性互转无需配置
  1. var dto =  PocoEmit.Mapper.Default.Convert<User, UserDTO>(new User { Id = 1, Name = "Jxj1" });
  2. var user =  PocoEmit.Mapper.Default.Convert<UserDTO, User>(new UserDTO { Id = 2, Name = "Jxj2" });
  3. var user3 =  PocoEmit.Mapper.Default.Convert<UserDTO2, User>(new UserDTO { Id = "3", Name = "张三" });
复制代码
三、一键开启集合类型转化配置



  • 通过UseCollection扩展方法给PocoEmit.Mapper增加集合功能
  • 扩展后PocoEmit.Mapper支持集合(含数组、列表及字典)的转化和复制
  • 支持实体类型包含集合成员的转化和复制
1. 启用集合配置

1.2 开启全局集合配置



  • 对所有Mapper启用集合
  • 应在使用所有Mapper实例之前配置,对已经完成初始化的Mapper实例无效
  1. CollectionContainer.GlobalUseCollection();
复制代码
1.1 对单个Mapper启用集合
  1. PocoEmit.Mapper.UseCollection();
复制代码
2.启用集合后集合互转无需配置
  1. User[] source = [new User { Id = 1, Name = "Jxj" }, new User { Id = 2, Name = "张三" }];
  2. UserDTO[] result = PocoEmit.Mapper.Default.Convert<User[], UserDTO[]>(source);
复制代码
  1. IEnumerable<User> source = [new User { Id = 1, Name = "Jxj" }, new User { Id = 2, Name = "张三" }];
  2. UserDTO[] result = PocoEmit.Mapper.Default.Convert<IEnumerable<User>, UserDTO[]>(source);
复制代码
  1. User[] source = [new User { Id = 1, Name = "Jxj" }, new User { Id = 2, Name = "张三" }];
  2. IEnumerable<UserDTO> result = PocoEmit.Mapper.Default.Convert<User[], IEnumerable<UserDTO>>(source);
复制代码
  1. Dictionary<int, User> source = new() { { 1, new User { Id = 1, Name = "Jxj" } } };
  2. UserDTO[] result = PocoEmit.Mapper.Default.Convert<Dictionary<int, User>, UserDTO[]>(source);
复制代码
  1. Dictionary<int, User> source = new() { { 1, new User { Id = 1, Name = "Jxj" } } };
  2. Dictionary<int, UserDTO> result = PocoEmit.Mapper.Default.Convert<Dictionary<int, User>, Dictionary<int, UserDTO>>(source);
复制代码
3.启用集合后集合成员互转无需配置
  1. var source = new UserArray { Name = "VIP", Users = [new User { Id = 1, Name = "Jxj" }, new User { Id = 2, Name = "张三" }] };
  2. UserDTOArray result = PocoEmit.Mapper.Default.Convert<UserArray, UserDTOArray>(source);
复制代码
四、自定义配置

1. Mapper全局配置



  • 全局配置对所有Mapper适用
  • 全局配置应在使用所有Mapper实例之前配置,对已经完成初始化的Mapper实例无效
1.1 全局配置映射规则
  1. PocoEmit.Mapper.GlobalConfigure(mapper => {
  2.     mapper.ConfigureMap<User, UserDTO>()
  3.     .Source
  4.     .Ignore(nameof(User.Name));
  5. });
复制代码
1.2 全局配置内部缓存字典大小



  • 配置适当大小可以减少内存占用和扩容
  1. PocoEmit.Mapper.GlobalOptions(options => {
  2.     // 转化器数量
  3.     options.ConverterCapacity = 100;
  4. });
复制代码
2. 配置单个Mapper
  1. PocoEmit.Mapper.Default.ConfigureMap<User, UserDTO>()
  2.     .Source
  3.     .Ignore(nameof(User.Name));
复制代码
3. 哪些需要配置

3.1 属性名前、后缀



  • AddPrefix设置前缀
  • AddSuffix设置后缀
  • ClearPrefix清空前缀
  1. public class UserCustomDTO(string userName)
  2. {
  3.     public int? UId { get; set; }
  4.     public string UName { get; } = userName;
  5. }
复制代码
3.1.1 源类型设置前缀
  1. IMapper mapper = Mapper.Create();
  2. mapper.ConfigureMap<UserCustomDTO, User>()
  3.     .Source
  4.     .AddPrefix("U");
  5. var source = new UserCustomDTO("Jxj2") { UId = 222 };
  6. var converter = mapper.GetConverter<UserCustomDTO, User>();
  7. User result = converter.Convert(source);
复制代码
3.1.2 目标类型设置前缀
  1. IMapper mapper = Mapper.Create();
  2. mapper.ConfigureMap<User, UserCustomDTO>()
  3.     .Dest
  4.     .AddPrefix("U");
  5. var source = new User { Id = 222, Name = "Jxj2" };
  6. var result = mapper.Convert<User, UserCustomDTO>(source);
复制代码
3.1.3 默认前缀



  • ConfigureMap会默认把源类型名作为目标类型前缀
  • ConfigureMap会默认把目标类型名作为源类型前缀
  • 如果默认前缀干扰到正常匹配,可以调用ClearPrefix清空前缀
  1. public class AutoUserDTO
  2. {
  3.     public string UserId { get; set; }
  4.     public string UserName { get; set; }
  5. }
  6. IMapper mapper = Mapper.Create();
  7. mapper.ConfigureMap();
  8. var source = new AutoUserDTO{ UserId = "222", UserName = "Jxj"  };
  9. var converter = mapper.GetConverter();
  10. User result = converter.Convert(source);
复制代码
3.2 属性一对一配置

3.2.1 通过Source配置



  • 直接MapTo或ForMember
  1. IMapper mapper = Mapper.Create();
  2. mapper.ConfigureMap<User, UserCustomDTO>()
  3.     .Source
  4.     .MapTo(nameof(User.Id), nameof(UserCustomDTO.UId))
  5.     .MapTo(nameof(User.Name), nameof(UserCustomDTO.UName));
  6. var source = new User { Id = 222, Name = "Jxj2" };
  7. var converter = mapper.GetConverter<User, UserCustomDTO>();
  8. UserCustomDTO result = converter.Convert(source);
复制代码
  1. IMapper mapper = Mapper.Create();
  2. mapper.ConfigureMap<User, UserCustomDTO>()
  3.     .Source
  4.     .ForMember(nameof(User.Id)).MapTo(nameof(UserCustomDTO.UId))
  5.     .ForMember(nameof(User.Name)).MapTo(nameof(UserCustomDTO.UName));
  6. var source = new User { Id = 222, Name = "Jxj2" };
  7. var converter = mapper.GetConverter<User, UserCustomDTO>();
  8. UserCustomDTO result = converter.Convert(source);
复制代码
3.2.2 通过Dest配置



  • 直接MapFrom或ForMember
  1. IMapper mapper = Mapper.Create();
  2. mapper.ConfigureMap<UserCustomDTO, User>()
  3.     .Dest
  4.     .MapFrom(nameof(User.Id), nameof(UserCustomDTO.UId))
  5.     .MapFrom(nameof(User.Name), nameof(UserCustomDTO.UName));
  6. var source = new UserCustomDTO("Jxj2") { UId = 222 };
  7. var converter = mapper.GetConverter<UserCustomDTO, User>();
  8. User result = converter.Convert(source);
复制代码
  1. IMapper mapper = Mapper.Create();
  2. mapper.ConfigureMap<UserCustomDTO, User>()
  3.     .Dest
  4.     .ForMember(nameof(User.Id)).MapFrom(nameof(UserCustomDTO.UId))
  5.     .ForMember(nameof(User.Name)).MapFrom(nameof(UserCustomDTO.UName));
  6. var source = new UserCustomDTO("Jxj2") { UId = 222 };
  7. var converter = mapper.GetConverter<UserCustomDTO, User>();
  8. User result = converter.Convert(source);
复制代码
3.3 忽略成员

3.3.1 被忽略的源类型成员不参与映射
  1. IMapper mapper = Mapper.Create();
  2. mapper.ConfigureMap<User, UserDTO>()
  3.     .Source
  4.     .Ignore(nameof(User.Name));
  5. var source = new User { Id = 111, Name = "Jxj" };
  6. var converter = mapper.GetConverter<User, UserDTO>();
  7. // result.Name == null
  8. UserDTO result = converter.Convert(source);
复制代码
3.3.2 被忽略的目标类型成员不会被匹配
  1. IMapper mapper = Mapper.Create();
  2. mapper.ConfigureMap<User, UserDTO>()
  3.     .Dest
  4.     .Ignore(nameof(UserDTO.Name));
  5. var source = new User { Id = 111, Name = "Jxj" };
  6. var converter = mapper.GetConverter<User, UserDTO>();
  7. // result.Name == null
  8. UserDTO result = converter.Convert(source);
复制代码
3.4 指定转化函数



  • 通过UseConvertFunc指定函数直接转化
  1. IMapper mapper = Mapper.Create();
  2. mapper.ConfigureMap<UserDTO, User>()
  3.     .UseConvertFunc(source => new User { Id= source.Id, Name = source.Name });
  4. var source = new UserDTO { Id = 111, Name = "Jxj" };
  5. var converter = mapper.GetConverter<UserDTO, User>();
  6. var result = converter.Convert(source);
复制代码
3.5 指定构造函数



  • 通过UseActivator指定构造函数
  • 执行完构造函数还会尝试匹配与UseConvertFunc是不同的
  1. IMapper mapper = Mapper.Create();
  2. mapper.ConfigureMap<User, UserCustomDTO>()
  3.     .UseActivator(u => new UserCustomDTO(u.Name) { UId = u.Id })
  4.     .Source
  5.     .MapTo(nameof(User.Id), nameof(UserCustomDTO.UId));
  6. var source = new User { Id = userId, Name = "Jxj2" };
  7. var converter = mapper.GetConverter<User, UserCustomDTO>();
  8. var result = converter.Convert(source);
复制代码
3.6 指定默认值

3.6.1 指定固定默认值
  1. IMapper mapper = Mapper.Create()
  2.     .UseDefault(Repository);
  3. var dto = new UserDTO { Id = 1, Name = "Jxj" };
  4. UserDomain user = mapper.Convert<UserDTO, UserDomain>(dto);
  5. class UserDomain(UserRepository repository, int id, string name)
  6. {
  7.     private readonly UserRepository _repository = repository;
  8.     public UserRepository Repository
  9.         => _repository;
  10.     public int Id { get; } = id;
  11.     public string Name { get; } = name;
  12.     // ...
  13. }
  14. static readonly UserRepository Repository = new();
  15. class UserRepository
  16. {
  17.     void Add(UserDomain user) { }
  18.     void Update(UserDomain entity) { }
  19.     void Remove(UserDomain entity) { }
  20. }
复制代码


  • 注: 如果不指定UserRepository的默认值,以上转化会报异常
  • 注: 以上例子示例给领域模型注入仓储
3.6.2 默认值指定工厂方法
  1. IMapper mapper = Mapper.Create()
  2.     .UseDefault(() => MessageId.NewId());
  3. var dto = new MessageDto { Message = "Hello UseDefault" };
  4. MessageDomain message = mapper.Convert<MessageDto, MessageDomain>(dto);
  5. class MessageDto
  6. {
  7.     public string Message { get; set; }
  8. }
  9. class MessageDomain(MessageId id, string message)
  10. {
  11.     public MessageId Id { get; } = id;
  12.     public string Message { get; } = message;
  13.     // ...
  14. }
  15. class MessageId(int id)
  16. {
  17.     private static int seed = 1;
  18.     public int Id { get; } = id;
  19.     public static MessageId NewId()
  20.         => new(seed++);
  21. }
复制代码


  • 注: 以上例子示例给领域模型注入自增Id
  • 注: 实际项目这里建议调用雪花Id
3.7 转化后补刀



  • 使用UseCheckAction配置转化检查逻辑用来补刀
  • 对于实在不方便配置映射规则的遗留属性进行补刀
  1. static void ConvertAddressCity(Customer customer, CustomerDTO dto)
  2. {
  3.     dto.AddressCity = customer.Address.City;
  4. }
  5. var mapper = PocoEmit.Mapper.Default;
  6. mapper.ConfigureMap<Customer, CustomerDTO>()
  7.     .UseCheckAction(ConvertAddressCity);
  8. CustomerDTO result = mapper.Convert<Customer, CustomerDTO>(source);
复制代码
五、PocoEmit的“继承”和“多态”

1. PocoEmit的“继承”



  • 通过全局配置实现类似继承的效果
  • 前面已经介绍了PocoEmit的全局配置
2. PocoEmit的“多态”



  • 对某些Mapper对象覆盖配置实现与其他Mapper不同的效果
  • 可以用不同的serviceKey注入容器,使用的时候就可以做到无感
2.1 举个发布平台需要“多态”的例子



  • 需要发布时间字段,平台内时间格式很好统一
  • 如果需要接入第三方数据,特别是国外的数据,格式很可能不一样
  • 牺牲性能用复杂逻辑去兼容也不是不可以
  • 这里建议提供多个Mapper的方案,不同渠道用不同的Mapper,每个Mapper只有极少的配置不同
  • 这就是PocoEmit“多态”的应用
2.2 再举个VIP的例子更明显



  • VIP客户提出各种格式化无关痛痒的问题
  • 一般就写if特殊处理了
  • 这类情况也适用PocoEmit“多态”
六、PocoEmit配合容器使用

1、容器注册转化器

1.1 默认注册

通过容器中默认的IMapper对象或Mapper.Global构造转化器
  1. services.UseConverter();
复制代码
1.2 指定IPoco对象注册
  1. services.UseConverter(PocoEmit.Mapper.Global);
复制代码
注: PocoEmit.Mapper.Global继承IPoco接口
1.3 隔离注册

指定IPoco和serviceKey注册
  1. IPoco poco = specialMapper;
  2. services.UseConverter(poco, "special");
复制代码
1.4 通过IPocoConverter注入

通过构造函数参数、属性等方式注入
  1. public sealed class Mapper(IPocoConverter<User, UserListDTO> converter)
  2.     : Mapper<Request, Response, IEnumerable<User>>
  3. {
  4.     // ...
  5. }
复制代码
2、容器注册复制器

2.1 默认注册

通过容器中默认的IMapper对象或Mapper.Global构造复制器
  1. services.UseCopier();
复制代码
2.2 指定IMapper对象注册
  1. services.UseCopier(PocoEmit.Mapper.Global);
复制代码
注: PocoEmit.Mapper.Global继承IMapper接口
2.3 隔离注册

指定IPoco和serviceKey注册
  1. IPoco poco = specialMapper;
  2. services.UseCopier(poco, "special");
复制代码
2.4 通过IPocoCopier注入

通过构造函数参数、属性等方式注入
  1. public sealed class Mapper(IPocoCopier<User, UserListDTO> copier)
  2.     : Mapper<Request, Response, IEnumerable<User>>
  3. {
  4.     // ...
  5. }
复制代码
源码托管地址: https://github.com/donetsoftwork/MyEmit ,也欢迎大家直接查看源码。
gitee同步更新:https://gitee.com/donetsoftwork/MyEmit
如果大家喜欢请动动您发财的小手手帮忙点一下Star。

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

相关推荐

您需要登录后才可以回帖 登录 | 立即注册