zoukankan      html  css  js  c++  java
  • C# 高性能对象映射(表达式树实现)

    前言

      上篇简单实现了对象映射,针对数组,集合,嵌套类并没有给出实现,这一篇继续完善细节。

    开源对象映射类库映射分析

     1.AutoMapper 

       实现原理:主要通过表达式树Api 实现对象映射 

       优点: .net功能最全的对象映射类库。

       缺点:当出现复杂类型和嵌套类型时性能直线下降,甚至不如序列化快

     2.TinyMapper

       实现原理:主要通过Emit 实现对象映射 

       优点:速度非常快。在处理复杂类型和嵌套类型性能也很好

       缺点:相对AutoMapper功能上少一些,Emit的实现方案,在代码阅读和调试上相对比较麻烦,而表达式树直接观察 DebugView中生成的代码结构便可知道问题所在

     3. 本文的对象映射库

      针对AutoMapper 处理复杂类型和嵌套类型时性能非常差的情况,自己实现一个表达式树版的高性能方案

    此篇记录下实现对象映射库的过程

      构造测试类

     1     public class TestA
     2     {
     3         public int Id { get; set; }
     4         public string Name { get; set; }
     5 
     6         public TestC TestClass { get; set; }
     7 
     8         public IEnumerable<TestC> TestLists { get; set; }
     9     }
    10 
    11     public class TestB
    12     {
    13         public int Id { get; set; }
    14         public string Name { get; set; }
    15 
    16         public TestD TestClass { get; set; }
    17 
    18         public TestD[] TestLists { get; set; }
    19     }
    20 
    21     public class TestC
    22     {
    23         public int Id { get; set; }
    24         public string Name { get; set; }
    25 
    26         public TestC SelfClass { get; set; }
    27     }
    28 
    29     public class TestD
    30     {
    31         public int Id { get; set; }
    32         public string Name { get; set; }
    33 
    34         public TestD SelfClass { get; set; }
    35     }

     1.初步实现

        利用表达式树给属性赋值 利用 Expresstion.New构造 var b=new B{};

     1       private static Func<TSource, TTarget> GetMap<TSource, TTarget>()
     2         {
     3             var sourceType = typeof(TSource);
     4             var targetType = typeof(TTarget);
     5 
     6             //构造 p=>
     7             var parameterExpression = Expression.Parameter(sourceType, "p");
     8 
     9             //构造 p=>new TTarget{ Id=p.Id,Name=p.Name };
    10             var memberBindingList = new List<MemberBinding>();
    11             foreach (var sourceItem in sourceType.GetProperties())
    12             {
    13                 var targetItem = targetType.GetProperty(sourceItem.Name);
    14                 if (targetItem == null || sourceItem.PropertyType != targetItem.PropertyType)
    15                     continue;
    16 
    17                 var property = Expression.Property(parameterExpression, sourceItem);
    18                 var memberBinding = Expression.Bind(targetItem, property);
    19                 memberBindingList.Add(memberBinding);
    20             }
    21             var memberInitExpression = Expression.MemberInit(Expression.New(targetType), memberBindingList);
    22 
    23             var lambda = Expression.Lambda<Func<TSource, TTarget>>(memberInitExpression, parameterExpression );
    24 
    25             Console.WriteLine(lambda);
    26             return lambda.Compile();
    27         }

      调用如下

    14 
    15     class Program
    16     {
    17         static void Main(string[] args)
    18         {
    19             var testA = new TestA { Id = 1, Name = "张三" };
    20             var func = Map<TestA, TestB>();
    21             TestB testB = func(testA);
    22             Console.WriteLine($"testB.Id={testB.Id},testB.Name={testB.Name}");
    23             Console.ReadLine();
    24         }
    25     }

      输出结果

     

    总结:此方法需要调用前需要手动编译下,然后再调用委托没有缓存委托,相对麻烦。

    2.缓存实现

       利用静态泛型类缓存泛型委托

     1     public class DataMapper<TSource, TTarget>
     2     {
     3         private static Func<TSource, TTarget> MapFunc { get; set; }
     4 
     5         public static TTarget Map(TSource source)
     6         {
     7             if (MapFunc == null)
     8                 MapFunc = GetMap();//方法在上边
     9             return MapFunc(source);
    10         }11    }

       调用方法

    1         static void Main(string[] args)
    2         {
    3             var testA = new TestA { Id = 1, Name = "张三" };
    4             TestB testB = DataMapper<TestA, TestB>.Map(testA);//委托不存在时自动生成,存在时调用静态缓存
    5 
    6             Console.WriteLine($"testB.Id={testB.Id},testB.Name={testB.Name}");
    7             Console.ReadLine();
    8         }

       输出结果

     

      总结:引入静态泛型类能解决泛型委托缓存提高性能,但是有两个问题  1.当传入参数为null时 则会抛出空引用异常 2.出现复杂类型上述方法便不能满足了

    3.解决参数为空值和复杂类型的问题

        首先先用常规代码实现下带有复杂类型赋值的情况

     1 public TestB GetTestB(TestA testA)
     2         {
     3             TestB testB;
     4             if (testA != null)
     5             {
     6                 testB = new TestB();
     7                 testB.Id = testA.Id;
     8                 testB.Name = testA.Name;
     9                 if (testA.TestClass != null)
    10                 {
    11                     testB.TestClass = new TestD();
    12                     testB.TestClass.Id = testA.TestClass.Id;
    13                     testB.TestClass.Name = testA.TestClass.Name;
    14                 }
    15             }
    16             else
    17             {
    18                 testB = null;
    19             }
    20             return testB;
    21         }

      将上面的代码翻译成表达式树

     1         private static Func<TSource, TTarget> GetMap()
     2         {
     3             var sourceType = typeof(TSource);
     4             var targetType = typeof(TTarget);
     5 
     6             //Func委托传入变量
     7             var parameter = Expression.Parameter(sourceType);
     8 
     9             //声明一个返回值变量
    10             var variable = Expression.Variable(targetType);
    11             //创建一个if条件表达式
    12             var test = Expression.NotEqual(parameter, Expression.Constant(null, sourceType));// p==null;
    13             var ifTrue = Expression.Block(GetExpression(parameter, variable, sourceType, targetType));
    14             var IfThen = Expression.IfThen(test, ifTrue);
    15 
    16             //构造代码块 
    17             var block = Expression.Block(new[] { variable }, parameter, IfThen, variable);
    18 
    19             var lambda = Expression.Lambda<Func<TSource, TTarget>>(block, parameter);
    20             return lambda.Compile();
    21         }
    22 
    23         private static List<Expression> GetExpression(Expression parameter, Expression variable, Type sourceType, Type targetType)
    24         {
    25             //创建一个表达式集合
    26             var expressions = new List<Expression>();
    27 
    28             expressions.Add(Expression.Assign(variable, Expression.MemberInit(Expression.New(targetType))));
    29 
    30             foreach (var targetItem in targetType.GetProperties().Where(x => x.PropertyType.IsPublic && x.CanWrite))
    31             {
    32                 var sourceItem = sourceType.GetProperty(targetItem.Name);
    33 
    34                 //判断实体的读写权限
    35                 if (sourceItem == null || !sourceItem.CanRead || sourceItem.PropertyType.IsNotPublic)
    36                     continue;
    37 
    38                 var sourceProperty = Expression.Property(parameter, sourceItem);
    39                 var targetProperty = Expression.Property(variable, targetItem);
    40 
    41                 //判断都是class 且类型不相同时
    42                 if (targetItem.PropertyType.IsClass && sourceItem.PropertyType.IsClass && targetItem.PropertyType != sourceItem.PropertyType)
    43                 {
    44                     if (targetItem.PropertyType != targetType)//不处理嵌套循环的情况
    45                     {
    46                         //由于类型是class 所以默认值是null
    47                         var testItem = Expression.NotEqual(sourceProperty, Expression.Constant(null, sourceItem.PropertyType));
    48 
    49                         var itemExpressions = GetExpression(sourceProperty, targetProperty, sourceItem.PropertyType, targetItem.PropertyType);
    50                         var ifTrueItem = Expression.Block(itemExpressions);
    51 
    52                         var IfThenItem = Expression.IfThen(testItem, ifTrueItem);
    53                         expressions.Add(IfThenItem);
    54 
    55                         continue;
    56                     }
    57                 }
    58 
    59                 //目标值类型时 且两者类型不一致时跳过
    60                 if (targetItem.PropertyType != sourceItem.PropertyType)
    61                     continue;
    62 
    63                 expressions.Add(Expression.Assign(targetProperty, sourceProperty));
    64             }
    65 
    66             return expressions;
    67         }

    总结:此方案,运用 Expression.IfThen(testItem, ifTrueItem) 判断空值问题,通过递归调用 GetExpression()方法,处理复杂类型。 但是。。。针对嵌套类仍然不能解决。因为表达式树是在实际调用方法之前就生成的,在没有实际的

               参数值传入之前,生成的表达式是不知道有多少层级的。有个比较low的方案是,预先设定嵌套层级为10层,然后生成一个有10层 if(P!=null) 的判断。如果传入的参数层级超过10层了呢,就得手动调整生成的树,此方案也否决。

               最后得出的结论只能在表达式中动态调用方法。

    4.最终版本

       通过动态调用方法解决嵌套类,代码如下

      using static System.Linq.Expressions.Expression;
        public static class Mapper<TSource, TTarget> where TSource : class where TTarget : class
        {
    public readonly static Func<TSource, TTarget> MapFunc = GetMapFunc();
    
    public readonly static Action<TSource, TTarget> MapAction = GetMapAction();
    
    /// <summary>
    /// 将对象TSource转换为TTarget
    /// </summary>
    /// <param name="source"></param>
    /// <returns></returns>
    public static TTarget Map(TSource source) => MapFunc(source);
    
    public static List<TTarget> MapList(IEnumerable<TSource> sources)=> sources.Select(MapFunc).ToList();
    
    
    
    /// <summary>
    /// 将对象TSource的值赋给给TTarget
    /// </summary>
    /// <param name="source"></param>
    /// <param name="target"></param>
    public static void Map(TSource source, TTarget target) => MapAction(source, target);
    
    private static Func<TSource, TTarget> GetMapFunc()
            {
                var sourceType = typeof(TSource);
                var targetType = typeof(TTarget);
                //Func委托传入变量
                var parameter = Parameter(sourceType, "p");
    
                var memberBindings = new List<MemberBinding>();
                var targetTypes = targetType.GetProperties().Where(x => x.PropertyType.IsPublic && x.CanWrite);
                foreach (var targetItem in targetTypes)
                {
                    var sourceItem = sourceType.GetProperty(targetItem.Name);
    
                    //判断实体的读写权限
                    if (sourceItem == null || !sourceItem.CanRead || sourceItem.PropertyType.IsNotPublic)
                        continue;
    
                    //标注NotMapped特性的属性忽略转换
                    if (sourceItem.GetCustomAttribute<NotMappedAttribute>() != null)
                        continue;
    
                    var sourceProperty = Property(parameter, sourceItem);
    
                    //当非值类型且类型不相同时
                    if (!sourceItem.PropertyType.IsValueType && sourceItem.PropertyType != targetItem.PropertyType)
                    {
                        //判断都是(非泛型)class
                        if (sourceItem.PropertyType.IsClass && targetItem.PropertyType.IsClass &&
                            !sourceItem.PropertyType.IsGenericType && !targetItem.PropertyType.IsGenericType)
                        {
                            var expression = GetClassExpression(sourceProperty, sourceItem.PropertyType, targetItem.PropertyType);
                            memberBindings.Add(Bind(targetItem, expression));
                        }
    
                        //集合数组类型的转换
                        if (typeof(IEnumerable).IsAssignableFrom(sourceItem.PropertyType) && typeof(IEnumerable).IsAssignableFrom(targetItem.PropertyType))
                        {
                            var expression = GetListExpression(sourceProperty, sourceItem.PropertyType, targetItem.PropertyType);
                            memberBindings.Add(Bind(targetItem, expression));
                        }
    
                        continue;
                    }
    
                    if (targetItem.PropertyType != sourceItem.PropertyType)
                        continue;
    
                    memberBindings.Add(Bind(targetItem, sourceProperty));
                }
    
                //创建一个if条件表达式
                var test = NotEqual(parameter, Constant(null, sourceType));// p==null;
                var ifTrue = MemberInit(New(targetType), memberBindings);
                var condition = Condition(test, ifTrue, Constant(null, targetType));
    
                var lambda = Lambda<Func<TSource, TTarget>>(condition, parameter);
                return lambda.Compile();
            }
    
            /// <summary>
            /// 类型是clas时赋值
            /// </summary>
            /// <param name="sourceProperty"></param>
            /// <param name="targetProperty"></param>
            /// <param name="sourceType"></param>
            /// <param name="targetType"></param>
            /// <returns></returns>
            private static Expression GetClassExpression(Expression sourceProperty, Type sourceType, Type targetType)
            {
                //条件p.Item!=null    
                var testItem = NotEqual(sourceProperty, Constant(null, sourceType));
    
                //构造回调 Mapper<TSource, TTarget>.Map()
                var mapperType = typeof(Mapper<,>).MakeGenericType(sourceType, targetType);
                var iftrue = Call(mapperType.GetMethod(nameof(Map), new[] { sourceType }), sourceProperty);
    
                var conditionItem = Condition(testItem, iftrue, Constant(null, targetType));
    
                return conditionItem;
            }
    
            /// <summary>
            /// 类型为集合时赋值
            /// </summary>
            /// <param name="sourceProperty"></param>
            /// <param name="targetProperty"></param>
            /// <param name="sourceType"></param>
            /// <param name="targetType"></param>
            /// <returns></returns>
            private static Expression GetListExpression(Expression sourceProperty, Type sourceType, Type targetType)
            {
                //条件p.Item!=null    
                var testItem = NotEqual(sourceProperty, Constant(null, sourceType));
    
                //构造回调 Mapper<TSource, TTarget>.MapList()
                var sourceArg = sourceType.IsArray ? sourceType.GetElementType() : sourceType.GetGenericArguments()[0];
                var targetArg = targetType.IsArray ? targetType.GetElementType() : targetType.GetGenericArguments()[0];
                var mapperType = typeof(Mapper<,>).MakeGenericType(sourceArg, targetArg);
    
                var mapperExecMap = Call(mapperType.GetMethod(nameof(MapList), new[] { sourceType }), sourceProperty);
    
                Expression iftrue;
                if (targetType == mapperExecMap.Type)
                {
                    iftrue = mapperExecMap;
                }
                else if (targetType.IsArray)//数组类型调用ToArray()方法
                {
                    iftrue = Call(mapperExecMap, mapperExecMap.Type.GetMethod("ToArray"));
                }
                else if (typeof(IDictionary).IsAssignableFrom(targetType))
                {
                    iftrue = Constant(null, targetType);//字典类型不转换
                }
                else
                {
                    iftrue = Convert(mapperExecMap, targetType);
                }
    
                var conditionItem = Condition(testItem, iftrue, Constant(null, targetType));
    
                return conditionItem;
            }
    
            private static Action<TSource, TTarget> GetMapAction()
            {
                var sourceType = typeof(TSource);
                var targetType = typeof(TTarget);
                //Func委托传入变量
                var sourceParameter = Parameter(sourceType, "p");
    
                var targetParameter = Parameter(targetType, "t");
    
                //创建一个表达式集合
                var expressions = new List<Expression>();
    
                var targetTypes = targetType.GetProperties().Where(x => x.PropertyType.IsPublic && x.CanWrite);
                foreach (var targetItem in targetTypes)
                {
                    var sourceItem = sourceType.GetProperty(targetItem.Name);
    
                    //判断实体的读写权限
                    if (sourceItem == null || !sourceItem.CanRead || sourceItem.PropertyType.IsNotPublic)
                        continue;
    
                    //标注NotMapped特性的属性忽略转换
                    if (sourceItem.GetCustomAttribute<NotMappedAttribute>() != null)
                        continue;
    
                    var sourceProperty = Property(sourceParameter, sourceItem);
                    var targetProperty = Property(targetParameter, targetItem);
    
                    //当非值类型且类型不相同时
                    if (!sourceItem.PropertyType.IsValueType && sourceItem.PropertyType != targetItem.PropertyType)
                    {
                        //判断都是(非泛型)class
                        if (sourceItem.PropertyType.IsClass && targetItem.PropertyType.IsClass &&
                            !sourceItem.PropertyType.IsGenericType && !targetItem.PropertyType.IsGenericType)
                        {
                            var expression = GetClassExpression(sourceProperty, sourceItem.PropertyType, targetItem.PropertyType);
                            expressions.Add(Assign(targetProperty, expression));
                        }
    
                        //集合数组类型的转换
                        if (typeof(IEnumerable).IsAssignableFrom(sourceItem.PropertyType) && typeof(IEnumerable).IsAssignableFrom(targetItem.PropertyType))
                        {
                            var expression = GetListExpression(sourceProperty, sourceItem.PropertyType, targetItem.PropertyType);
                            expressions.Add(Assign(targetProperty, expression));
                        }
    
                        continue;
                    }
    
                    if (targetItem.PropertyType != sourceItem.PropertyType)
                        continue;
    
    
                    expressions.Add(Assign(targetProperty, sourceProperty));
                }
    
                //当Target!=null判断source是否为空
                var testSource = NotEqual(sourceParameter, Constant(null, sourceType));
                var ifTrueSource = Block(expressions);
                var conditionSource = IfThen(testSource, ifTrueSource);
    
                //判断target是否为空
                var testTarget = NotEqual(targetParameter, Constant(null, targetType));
                var conditionTarget = IfThen(testTarget, conditionSource);
    
                var lambda = Lambda<Action<TSource, TTarget>>(conditionTarget, sourceParameter, targetParameter);
                return lambda.Compile();
            }
        }

    输出的 表达式

    格式化后

     1 p => IIF((p != null), 
     2      new TestB() 
     3      {
     4        Id = p.Id, 
     5        Name = p.Name, 
     6        TestClass = IIF(
     7                    (p.TestClass != null),
     8                     Map(p.TestClass),
     9                     null
    10                     ),
    11        TestLists = IIF(
    12                      (p.TestLists != null),
    13                       MapList(p.TestLists).ToArray(),
    14                       null
    15                      )
    16        },
    17        null)

    说明 Map(p.TestClass)   MapList(p.TestLists).ToArray(),  完整的信息为 Mapper<TestC,TestD>.Map()   Mapper<TestC,TestD>.MapList()  

       总结:解决嵌套类的核心代码

    101             //构造回调 Mapper<TSource, TTarget>.Map()
    102             var mapperType = typeof(DataMapper<,>).MakeGenericType(sourceType, targetType);
    103             var mapperExecMap = Expression.Call(mapperType.GetMethod(nameof(Map), new[] { sourceType }), sourceProperty);

       利用Expression.Call  根据参数类型动态生成 对象映射的表达式

    性能测试

       写了这么多最终目的还是为了解决性能问题,下面将对比下性能

      1.测试类

      1     public static class MapperTest
      2     {
      3         //执行次数
      4         public static int Count = 100000;
      5 
      6         //简单类型
      7         public static void Nomal()
      8         {
      9             Console.WriteLine($"******************简单类型:{Count / 10000}万次执行时间*****************");
     10             var model = new TestA
     11             {
     12                 Id =1,
     13                 Name = "张三",
     14             };
     15 
     16             //计时
     17             var sw = Stopwatch.StartNew();
     18             for (int i = 0; i < Count; i++)
     19             {
     20                 if (model != null)
     21                 {
     22                     var b = new TestB
     23                     {
     24                         Id = model.Id,
     25                         Name = model.Name,
     26                     };
     27                 }
     28             }
     29             sw.Stop();
     30             Console.WriteLine($"原生的时间:{sw.ElapsedMilliseconds}ms");
     31 
     32             Exec(model);
     33         }
     34 
     35         //复杂类型
     36         public static void Complex()
     37         {
     38             Console.WriteLine($"********************复杂类型:{Count / 10000}万次执行时间*********************");
     39             var model = new TestA
     40             {
     41                 Id = 1,
     42                 Name = "张三",
     43                 TestClass = new TestC
     44                 {
     45                     Id = 2,
     46                     Name = "lisi",
     47                 },
     48             };
     49 
     50             //计时
     51             var sw = Stopwatch.StartNew();
     52             for (int i = 0; i < Count; i++)
     53             {
     54 
     55                 if (model != null)
     56                 {
     57                     var b = new TestB
     58                     {
     59                         Id = model.Id,
     60                         Name = model.Name,
     61                     };
     62                     if (model.TestClass != null)
     63                     {
     64                         b.TestClass = new TestD
     65                         {
     66                             Id = i,
     67                             Name = "lisi",
     68                         };
     69                     }
     70                 }
     71             }
     72             sw.Stop();
     73             Console.WriteLine($"原生的时间:{sw.ElapsedMilliseconds}ms");
     74             Exec(model);
     75         }
     76 
     77         //嵌套类型
     78         public static void Nest()
     79         {
     80             Console.WriteLine($"*****************嵌套类型:{Count / 10000}万次执行时间*************************");
     81             var model = new TestA
     82             {
     83                 Id = 1,
     84                 Name = "张三",
     85                 TestClass = new TestC
     86                 {
     87                     Id = 1,
     88                     Name = "lisi",
     89                     SelfClass = new TestC
     90                     {
     91                         Id = 2,
     92                         Name = "lisi",
     93                         SelfClass = new TestC
     94                         {
     95                             Id = 3,
     96                             Name = "lisi",
     97                             SelfClass = new TestC
     98                             {
     99                                 Id = 4,
    100                                 Name = "lisi",
    101                             },
    102                         },
    103                     },
    104                 },
    105             };
    106             //计时
    107             var item = model;
    108             var sw = Stopwatch.StartNew();
    109             for (int i = 0; i < Count; i++)
    110             {
    111                 //这里每一步需要做非空判断的,书写太麻烦省去了
    112                 if (model != null)
    113                 {
    114                     var b = new TestB
    115                     {
    116                         Id = model.Id,
    117                         Name = model.Name,
    118                         TestClass = new TestD
    119                         {
    120                             Id = model.TestClass.Id,
    121                             Name = model.TestClass.Name,
    122                             SelfClass = new TestD
    123                             {
    124                                 Id = model.TestClass.SelfClass.Id,
    125                                 Name = model.TestClass.SelfClass.Name,
    126                                 SelfClass = new TestD
    127                                 {
    128                                     Id = model.TestClass.SelfClass.SelfClass.Id,
    129                                     Name = model.TestClass.SelfClass.SelfClass.Name,
    130                                     SelfClass = new TestD
    131                                     {
    132                                         Id = model.TestClass.SelfClass.SelfClass.SelfClass.Id,
    133                                         Name = model.TestClass.SelfClass.SelfClass.SelfClass.Name,
    134                                     },
    135                                 },
    136                             },
    137                         },
    138                     };
    139                 }
    140             }
    141             sw.Stop();
    142             Console.WriteLine($"原生的时间:{sw.ElapsedMilliseconds}ms");
    143 
    144             Exec(model);
    145         }
    146 
    147         //集合
    148         public static void List()
    149         {
    150             Console.WriteLine($"********************集合类型:{Count/10000}万次执行时间***************************");
    151 
    152             var model = new TestA
    153             {
    154                 Id = 1,
    155                 Name = "张三",
    156                 TestLists = new List<TestC> {
    157                             new TestC{
    158                              Id = 1,
    159                             Name =  "张三",
    160                            },
    161                             new TestC{
    162                             Id = -1,
    163                             Name =  "张三",
    164                            },
    165                         }
    166             };
    167 
    168 
    169             //计时
    170             var sw = Stopwatch.StartNew();
    171             for (int i = 0; i < Count; i++)
    172             {
    173                 var item = model;
    174                 if (item != null)
    175                 {
    176                     var b = new TestB
    177                     {
    178                         Id = item.Id,
    179                         Name = item.Name,
    180                         TestLists = new List<TestD> {
    181                             new TestD{
    182                                    Id = item.Id,
    183                             Name = item.Name,
    184                            },
    185                             new TestD{
    186                             Id = -item.Id,
    187                             Name = item.Name,
    188                            },
    189                         }.ToArray()
    190                     };
    191                 }
    192             }
    193             sw.Stop();
    194             Console.WriteLine($"原生的时间:{sw.ElapsedMilliseconds}ms");
    195 
    196             Exec(model);
    197         }
    198 
    199         public static void Exec(TestA model)
    200         {
    201             //表达式
    202             Mapper<TestA, TestB>.Map(model);
    203             var sw = Stopwatch.StartNew();
    204             for (int i = 0; i < Count; i++)
    205             {
    206                 var b = Mapper<TestA, TestB>.Map(model);
    207             }
    208             sw.Stop();
    209             Console.WriteLine($"表达式的时间:{sw.ElapsedMilliseconds}ms");
    210 
    211             //AutoMapper
    212             sw.Restart();
    213             for (int i = 0; i < Count; i++)
    214             {
    215                 var b = AutoMapper.Mapper.Map<TestA, TestB>(model);
    216             }
    217             sw.Stop();
    218             Console.WriteLine($"AutoMapper时间:{sw.ElapsedMilliseconds}ms");
    219 
    220             //TinyMapper
    221             sw.Restart();
    222             for (int i = 0; i < Count; i++)
    223             {
    224                 var b = TinyMapper.Map<TestA, TestB>(model);
    225             }
    226             sw.Stop();
    227             Console.WriteLine($"TinyMapper时间:{sw.ElapsedMilliseconds}ms");
    228         }
    229     }
    230 
    231 

    2.调用测试

     1         static void Main(string[] args)
     2         {
     3             AutoMapper.Mapper.Initialize(cfg => cfg.CreateMap<TestA, TestB>());
     4             TinyMapper.Bind<TestA, TestB>();
     5             Mapper<TestA, TestB>.Map(new TestA());
     6 
     7 
     8             MapperTest.Count = 10000;
     9             MapperTest.Nomal();
    10             MapperTest.Complex();
    11             MapperTest.Nest();
    12             MapperTest.List();
    13 
    14             MapperTest.Count = 100000;
    15             MapperTest.Nomal();
    16             MapperTest.Complex();
    17             MapperTest.Nest();
    18             MapperTest.List();
    19 
    20             MapperTest.Count = 1000000;
    21             MapperTest.Nomal();
    22             MapperTest.Complex();
    23             MapperTest.Nest();
    24             MapperTest.List();
    25 
    26             MapperTest.Count = 10000000;
    27             MapperTest.Nomal();
    28             MapperTest.Complex();
    29             MapperTest.Nest();
    30             MapperTest.List();
    31 
    32 
    33             Console.WriteLine($"------------结束--------------------");
    34             Console.ReadLine();
    35         }

    3.结果

    1万次

    10万次

     

    100万次

    1000万次

    上图结果AutoMapper 在非简单类型的转换上比其他方案有50倍以上的差距,几乎就跟反射的结果一样。

    作者:costyuan

    GitHub地址:https://github.com/bieyuan/.net-core-DTO

    地址:http://www.cnblogs.com/castyuan/p/9324088.html
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。 
    如果文中有什么错误,欢迎指出,谢谢! 

  • 相关阅读:
    TCP_UCP通信原理及案例
    JavaScript高级笔记DOM与BOM
    JavaScript基本语法,基本对象,正则表达式
    JDBC连接池&JDBCTemplate&Sping JDBC
    JDBC,JDBCUtils,JDBC控制事务
    自动化工具ansible(0——准备部署工作)
    监控软件篇——prometheus+exporter组件+grafana
    命令工具篇
    sed 命令备忘
    ES6数据分组
  • 原文地址:https://www.cnblogs.com/castyuan/p/9324088.html
Copyright © 2011-2022 走看看