ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

一个高性能的简易Model映射类

2021-06-06 10:55:49  阅读:151  来源: 互联网

标签:映射 No TTarget item 高性能 Model Expression 表达式 lambda


我们有各种理由在项目中引入DTO(数据传输对象),因此也有了映射Model与DTO的需求。 要实现映射功能,我们要么自己写代码实现,要么使用现成的库(如AutoMapper)来实现。

但有时候,我们仅仅需要映射少量的对象,并且不想引入库。那么这个时候我们只能自己写代码,于是“反射”信手拈来。 众所周知,在.NET 2.0的时候,反射的性能是非常低下的,直到.NET 4.0做了较大的优化提升。即便如此,在进行大量反射的情形下,其性能还是难以让人满意。值得庆幸的是,.NET 3.5 推出了LinQ,推出了表达式树功能,因此我们可以构造表达式,并将其编译结果缓存起来,这样就无需重复反射,直接调用,大大提升了性能。

 

下面是一份简易的映射类,注释完善,有需要的同学可以自行优化和改造。

 1   /// <summary>
 2     /// 模型自动映射。 Source ——> Target
 3     /// </summary>
 4     /// <remarks>
 5     ///  属性和字段名称全字匹配方式
 6     /// </remarks>
 7     public static class AutoMapper<TSource, TTarget>
 8        where TSource : class
 9        where TTarget : class, new()
10     {
11         static AutoMapper()
12         {
13             ExpressionMapper();
14         }
15 
16         private static Func<TSource, TTarget> _func = null;
17 
18         private static void ExpressionMapper()
19         {
20             Type targetType = typeof(TTarget);
21             Type sourceType = typeof(TSource);
22 
23             //创建一个lambda参数x,定义的对象为 TSource
24             ParameterExpression parameterExpression = Expression.Parameter(sourceType, "x");
25             //开始生成lambda表达式
26             List<MemberBinding> memberBindings = new List<MemberBinding>();
27 
28             foreach (var item in targetType.GetProperties())
29             {
30                 var property = sourceType.GetProperty(item.Name);
31 
32                 if (property == null) continue;
33 
34                 //为x参数表达式生成一个属性值
35                 MemberExpression propertyExpression = Expression.Property(parameterExpression, property);
36                 //将该属性初始化 eg:No=x.No
37                 MemberBinding memberBinding = Expression.Bind(item, propertyExpression);
38 
39                 memberBindings.Add(memberBinding);
40             }
41 
42             foreach (var item in typeof(TTarget).GetFields())
43             {
44                 var field = sourceType.GetField(item.Name);
45 
46                 if (field == null) continue;
47 
48                 //为x参数表达式生成一个字段值
49                 MemberExpression fieldExpression = Expression.Field(parameterExpression, field);
50                 //将该字段初始化
51                 MemberBinding memberBinding = Expression.Bind(item, fieldExpression);
52 
53                 memberBindings.Add(memberBinding);
54             }
55 
56             //调用默认无参构造函数,初始化一个 TTarget eg: new{No=x.No...}。 注意TTarget的泛型约束
57             MemberInitExpression memberInitExpression = Expression.MemberInit(Expression.New(targetType), memberBindings);
58             //创建lambda表达式  eg: x=>new{ No=x.No...}
59             Expression<Func<TSource, TTarget>> lambda = Expression.Lambda<Func<TSource, TTarget>>(memberInitExpression, parameterExpression);
60 
61             //将lambda表达式生成委托
62             _func = lambda.Compile();
63         }
64 
65         /// <summary>
66         /// 转换/映射
67         /// </summary>
68         /// <param name="sourceInstance">原始类型实例</param>
69         /// <returns>一个新的目标类型的实例</returns>
70         public static TTarget Trans(TSource sourceInstance)
71         {
72             return _func?.Invoke(sourceInstance);
73         }
74     }

 

使用静态构造函数,仅调用一次,然后用变量将表达式编译后的委托存储起来,下次直接调用,提升了性能。

 

标签:映射,No,TTarget,item,高性能,Model,Expression,表达式,lambda
来源: https://blog.51cto.com/XCracker/2871711

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有