zoukankan      html  css  js  c++  java
  • 一个高性能的简易Model映射类

    我们有各种理由在项目中引入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     }

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

  • 相关阅读:
    ext文件系统机制原理剖析
    win10企业版无法访问共享文件夹
    Linux 系统 CPU 的性能监控及调优
    MySQL延时复制简介
    MySQL迁移升级解决方案
    Docker 微服务教程安装WordPress
    java
    pom.xml
    sharding-jdbc
    java-MyBatis可视化代码生成工具
  • 原文地址:https://www.cnblogs.com/WinHEC/p/A_simple_and_Hi-PERF_model_mapper.html
Copyright © 2011-2022 走看看