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
本文版權歸作者和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接,否則保留追究法律責任的權利。 
如果文中有什么錯誤,歡迎指出,謝謝! 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM