前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >重复造轮子 SimpleMapper (转载非原创)

重复造轮子 SimpleMapper (转载非原创)

作者头像
wxilejun
修改2022-09-15 13:13:27
4750
修改2022-09-15 13:13:27
举报
文章被收录于专栏:wxilejun的专栏wxilejun的专栏

转载来源: https://www.cnblogs.com/zhouandke/p/16695968.html

  接手的项目还在用 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的代码,使用示例:

代码语言:javascript
复制
 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<Person, PersonDto>((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<PersonDto>(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 代码地址

本文系转载,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文系转载前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
文件存储
文件存储(Cloud File Storage,CFS)为您提供安全可靠、可扩展的共享文件存储服务。文件存储可与腾讯云服务器、容器服务、批量计算等服务搭配使用,为多个计算节点提供容量和性能可弹性扩展的高性能共享存储。腾讯云文件存储的管理界面简单、易使用,可实现对现有应用的无缝集成;按实际用量付费,为您节约成本,简化 IT 运维工作。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档