首先申明两个 类名不同但其他属性完全一致的两个类
1 /// <summary> 2 /// 实体类 3 /// </summary> 4 public class People 5 { 6 public int Age { get; set; } 7 public string Name { get; set; } 8 public int Id; 9 10 } 11 /// <summary> 12 /// 实体类Target 13 /// PeopleDTO 14 /// </summary> 15 public class PeopleCopy 16 { 17 public int Age { get; set; } 18 public string Name { get; set; } 19 public int Id; 20 }
在上面我们可以看到两个类名不一样但是其他全部一样的两个实体类
1,如何使 People = PeopleCopy直接使用强砖不行,简单的说明一下,因为两个类,不是父子性关系所有两个类不能进行强转
现在可以用的方法大致分为几类我将一个一个进行对比并说说其中的优势
硬编码转换, Json对象转换,反射对象,Experssion加字典缓存, Experssion加泛型缓存
//硬编码转换无疑是一种效率最高的一种方法但是,可变性相当的差,当属性有成千上百时,耗时耗力并且不易迁移
1 People people = new People() 2 { 3 Id = 11, 4 Name = "YZM", 5 Age = 31 6 }; 7 PeopleCopy peopleCopy = new PeopleCopy() 8 { 9 Id = people.Id, 10 Name = people.Name, 11 Age = people.Age 12 };
1 public class SerializeMapper 2 { 3 4 /* 序列化本身其实很强只是json序列化不是为转化二生成的每一次的转化Json都需要转化两次一次由对象转化为Json对象,再由Json对象转化成对象所以相当耗费时间和效能 */ 5 /// <summary> 6 /// 序列化反序列化方式 7 /// </summary> 8 /// <typeparam name="TIn"></typeparam> 9 /// <typeparam name="TOut"></typeparam> 10 public static TOut Trans<TIn, TOut>(TIn tIn) 11 { 12 return JsonConvert.DeserializeObject<TOut>(JsonConvert.SerializeObject(tIn)); 13 } 14 }
1 /*反射是一种比较耗费效率的一种方法 2 如果反射千次万次的话可想效率的占用 3 */ 4 public class ReflectionMapper 5 { 6 /// <summary> 7 /// 反射 8 /// </summary> 9 /// <typeparam name="TIn"></typeparam> 10 /// <typeparam name="TOut"></typeparam> 11 /// <param name="tIn"></param> 12 /// <returns></returns> 13 public static TOut Trans<TIn, TOut>(TIn tIn) 14 { 15 TOut tOut = Activator.CreateInstance<TOut>(); 16 foreach (var itemOut in tOut.GetType().GetProperties()) 17 { 18 var propIn = tIn.GetType().GetProperty(itemOut.Name); 19 itemOut.SetValue(tOut, propIn.GetValue(tIn)); 20 } 21 foreach (var itemOut in tOut.GetType().GetFields()) 22 { 23 var fieldIn = tIn.GetType().GetField(itemOut.Name); 24 itemOut.SetValue(tOut, fieldIn.GetValue(tIn)); 25 } 26 return tOut; 27 } 28 }
1 /// <summary> 2 /// 生成表达式目录树 缓存 3 /// 其实就本身而言表达式目录树是十分快速的那为什么时间耗费稍微比较长了,这就要考虑到字典的问题了,字典Dictionary采用hash分布 通过Key来获取Value,在通过Key查找Values时耗费了相当的时间 4 /// 5 /// </summary> 6 public class ExpressionMapper 7 { 8 /// <summary> 9 /// 字典缓存--hash分布 10 /// </summary> 11 private static Dictionary<string, object> _Dic = new Dictionary<string, object>(); //超过一定的数量之后 在字典中获取值就会有性能损耗 12 13 /// <summary> 14 /// 字典缓存表达式树 15 /// </summary> 16 /// <typeparam name="TIn"></typeparam> 17 /// <typeparam name="TOut"></typeparam> 18 /// <param name="tIn"></param> 19 /// <returns></returns> 20 public static TOut Trans<TIn, TOut>(TIn tIn) 21 { 22 string key = string.Format("funckey_{0}_{1}", typeof(TIn).FullName, typeof(TOut).FullName); 23 if (!_Dic.ContainsKey(key)) 24 { 25 //动态的生成表达式 26 ParameterExpression parameterExpression = Expression.Parameter(typeof(TIn), "p"); 27 List<MemberBinding> memberBindingList = new List<MemberBinding>(); 28 foreach (var item in typeof(TOut).GetProperties()) 29 { 30 MemberExpression property = Expression.Property(parameterExpression, typeof(TIn).GetProperty(item.Name)); 31 MemberBinding memberBinding = Expression.Bind(item, property); 32 memberBindingList.Add(memberBinding); 33 } 34 foreach (var item in typeof(TOut).GetFields()) 35 { 36 MemberExpression property = Expression.Field(parameterExpression, typeof(TIn).GetField(item.Name)); 37 MemberBinding memberBinding = Expression.Bind(item, property); 38 memberBindingList.Add(memberBinding); 39 } 40 MemberInitExpression memberInitExpression = Expression.MemberInit(Expression.New(typeof(TOut)), memberBindingList.ToArray()); 41 Expression<Func<TIn, TOut>> lambda = Expression.Lambda<Func<TIn, TOut>>(memberInitExpression, new ParameterExpression[] 42 { 43 parameterExpression 44 }); 45 Func<TIn, TOut> func = lambda.Compile();//拼装是一次性的 46 _Dic[key] = func; 47 } 48 return ((Func<TIn, TOut>)_Dic[key]).Invoke(tIn); 49 } 50 }
1 /// <summary> 2 /// 生成表达式目录树 泛型缓存 3 /// Experssion的已经是相当迅速的了,加上泛型缓存不用采用Hash去查找Key的values这样速度再次加快所以,Experssion+泛型是一种比较理想的方式 4 /// </summary> 5 /// <typeparam name="TIn"></typeparam> 6 /// <typeparam name="TOut"></typeparam> 7 public class ExpressionGenericMapper<TIn, TOut>//Mapper`2 //正对于每两个不同类型的组合都会生成副本 8 { 9 private static Func<TIn, TOut> _FUNC = null;// 在每个副本中都有一个委托 10 static ExpressionGenericMapper() //静态构造函数 生成表达式目录树 11 { 12 ParameterExpression parameterExpression = Expression.Parameter(typeof(TIn), "p"); 13 List<MemberBinding> memberBindingList = new List<MemberBinding>(); 14 foreach (var item in typeof(TOut).GetProperties()) 15 { 16 MemberExpression property = Expression.Property(parameterExpression, typeof(TIn).GetProperty(item.Name)); 17 MemberBinding memberBinding = Expression.Bind(item, property); 18 memberBindingList.Add(memberBinding); 19 } 20 foreach (var item in typeof(TOut).GetFields()) 21 { 22 MemberExpression property = Expression.Field(parameterExpression, typeof(TIn).GetField(item.Name)); 23 MemberBinding memberBinding = Expression.Bind(item, property); 24 memberBindingList.Add(memberBinding); 25 } 26 MemberInitExpression memberInitExpression = Expression.MemberInit(Expression.New(typeof(TOut)), memberBindingList.ToArray()); 27 Expression<Func<TIn, TOut>> lambda = Expression.Lambda<Func<TIn, TOut>>(memberInitExpression, new ParameterExpression[] 28 { 29 parameterExpression 30 }); 31 _FUNC = lambda.Compile();//拼装是一次性的 转换成委托以后放入副本的静态变量中去 32 } 33 public static TOut Trans(TIn t) // 直接获取副本的静态变量(委托) 34 { 35 return _FUNC(t); 36 } 37 }
测试代码
1 /* 2 测试代码 3 */ 4 5 Console.WriteLine("****************************性能测试结果***************************"); 6 People people = new People() 7 { 8 Id = 11, 9 Name = "YZM", 10 Age = 31 11 }; 12 long common = 0; 13 long generic = 0; 14 long cache = 0; 15 long reflection = 0; 16 long serialize = 0; 17 { 18 Stopwatch watch = new Stopwatch(); 19 watch.Start(); 20 for (int i = 0; i < 100_000; i++) 21 { 22 PeopleCopy peopleCopy = new PeopleCopy() 23 { 24 Id = people.Id, 25 Name = people.Name, 26 Age = people.Age 27 }; 28 } 29 watch.Stop(); 30 common = watch.ElapsedMilliseconds; 31 } 32 { 33 Stopwatch watch = new Stopwatch(); 34 watch.Start(); 35 for (int i = 0; i < 100_000; i++) 36 { 37 PeopleCopy peopleCopy = ReflectionMapper.Trans<People, PeopleCopy>(people); 38 } 39 watch.Stop(); 40 reflection = watch.ElapsedMilliseconds; 41 } 42 { 43 Stopwatch watch = new Stopwatch(); 44 watch.Start(); 45 for (int i = 0; i < 100_000; i++) 46 { 47 PeopleCopy peopleCopy = SerializeMapper.Trans<People, PeopleCopy>(people); 48 } 49 watch.Stop(); 50 serialize = watch.ElapsedMilliseconds; 51 } 52 { 53 Stopwatch watch = new Stopwatch(); 54 watch.Start(); 55 for (int i = 0; i < 100_000; i++) 56 { 57 PeopleCopy peopleCopy = ExpressionMapper.Trans<People, PeopleCopy>(people); 58 } 59 watch.Stop(); 60 cache = watch.ElapsedMilliseconds; 61 } 62 { 63 Stopwatch watch = new Stopwatch(); 64 watch.Start(); 65 for (int i = 0; i < 100_000; i++) 66 { 67 PeopleCopy peopleCopy = ExpressionGenericMapper<People, PeopleCopy>.Trans(people); 68 } 69 watch.Stop(); 70 generic = watch.ElapsedMilliseconds; 71 } 72 Console.WriteLine($"common = { common} ms"); 73 Console.WriteLine($"reflection = { reflection} ms"); 74 Console.WriteLine($"serialize = { serialize} ms"); 75 Console.WriteLine($"cache = { cache} ms"); 76 Console.WriteLine($"generic = { generic} ms"); 77 } 78 79 }
从性能检测结果来看速度分别为
1,硬编码2,Experssion+泛型缓存3,Experssion+字典缓存4,反射Reflection5Json序列化