• 重复造轮子 SimpleMapper


      接手的项目还在用 TinyMapper 的一个早期版本用来做自动映射工具,TinyMapper 虽然速度快,但在配置里不能转换类型,比如 deleted 在数据库中用 0、1 表示,转换成实体模型时没法转换成 bool 类型,就为了这一个属性,就必须手写代码人工转换(怪不得有些 Mapper 作者认为 TinyMapper 是一个 toy)。
      于是试一试 AutoMapper,可是这货需要提前注册所有的映射关系,程序员本来就已经很累了。。。(最新版 TinyMapper 也要求提前注册所有映射关系)。
      找出以前使用过的 ValueInjecter,可扩展性很强,使用反射来实现。虽然我认为对现在处理器性能而言,快慢已经不太重要了,但它速度实在太慢了,有些测试项目消耗时间是 json反序列化的一半,TinyMapper 和 AutoMapper 均使用 emit 实现,非常接近手写代码的速度了。
      在 nuget.org 上找了找,还发现两个非常不错的 mapper:
      1. UltraMapper 不需要提前注册映射关系,而且使用 ReferenceTracking 解决了循环问题。
      2. HigLabo.Mapper 也不需要提前注册映射关系(看来牛人都对提前注册很不爽),支持 object 转换为Dictionary,提出了 PostAction 概念(自动映射出目标对象后,还可以执行自定义动作进行手工赋值,这样就不需要费力实现 Flattening 什么的了)。但试用过程中,发现不能实现 Array 到 List 的转换,而且作者也不打算改。。。

      既然各个 Mapper 都不太顺手,并且这段时间疫情封控,于是决定自己手撸一个POCO的 Mapper,目标如下:
      1. 不需要提前注册映射关系
      2. 像 json序列化/反序列化一样,同名属性尽可能映射(比如 int? 到 enum)
      3. 增加 HigLabo.Mapper的PostAction概念
      4. 使用 表达式树/Emit 提高速度

     

      编写过程中参考了 TinyMapper 和UltraMapper的代码,使用示例:

    复制代码
     1     public class Person
     2     {
     3         public int Id { get; set; }
     4 
     5         public string Name { get; set; }
     6         // Same Name, different type
     7         public byte? Age { get; set; }
     8     }
     9 
    10     public class PersonDto
    11     {
    12         public int Id { get; set; }
    13 
    14         public string Name { get; set; }
    15 
    16         public int? Age { get; set; }
    17 
    18         public string Description { get; set; }
    19     }
    20 
    21     class Program
    22     {
    23         static void Main(string[] args)
    24         {
    25             // register PostAction
    26             ZK.Mapper.SimpleMapper.Default.SetPostAction((p, dto) =>
    27             {
    28                 if (dto == null)
    29                 {
    30                     return dto;
    31                 }
    32                 dto.Description = p.Age.HasValue ? $"{p.Name} age is {p.Age}" : $"{p.Name} age is unknown";
    33                 return dto;
    34             });
    35 
    36             var p = new Person()
    37             {
    38                 Id = 1,
    39                 Name = "john",
    40                 Age = 32
    41             };
    42 
    43             var dto = ZK.Mapper.SimpleMapper.Default.Map(p);
    44             Console.WriteLine(dto.Description);
    45         }
    46     }
    复制代码

     

      写写这里面的总结吧
      1. 内部Mapper都是泛型的,但使用时传入的source很可能是 object,所以都是使用 反射创建泛型化的Mapper实例,然后建立TypePair的对应关系,这样就解偶了泛型
      2. Emit 和 表达式树原理都是一样的,建立IL代码,所以效率非常接近
      3. 如果能像 AutoMapper 那样提前注册所有映射关系,速度优化的手段会更多,估计这也是 TinyMapper 转成提前注册的原因吧。很多 Mapper 的性能测试都号称比 AutoMapper 快,但引用的都是老版本的 AutoMapper,但现在 AutoMapper 非常快,在一些简单测试里赶上了 TinyMapper。如果添加了很多特色功能,却很拖累速度。当然我还是觉得只要不是数量级的差距,都不太重要。
      4. 我的潜意识里 SimpleMapper 就为解决当前项目的问题,比如从数据库中读出来对象,映射成Dto后,就不会被再使用了,所以SimpleMapper默认是浅拷贝。所以我也不打算发布到nuget。
      5. SimpleMapper 功能不多,也没有为性能做太多优化,所以结构比较清晰,有兴趣的朋友阅读起来应该不难。

     

      SimpleMapper 代码地址

  • 相关阅读:
    【学习记录】Windows10蓝屏问题排查
    C++-哈希Hash
    分享教学项目:开源一个对象映射框架
    【100天精通Python】Day63:Python可视化_Matplotlib绘制子图,子图网格布局属性设置等示例+代码
    让程序员少吃些哑巴亏——认识论辩的逻辑谬误和辩驳原则
    md5的特点以及加密原理
    好心情平台:30分钟就可改善抑郁情绪的运动处方
    java web学习总结
    vue使用jsencrypt实现rsa前端加密
    OZON测评自养号技巧,提升店铺权重和销量,避免恶意跟卖
  • 原文地址:https://www.cnblogs.com/zhouandke/p/16695968.html