对于浅拷贝和深拷贝,前面的文章已经说明了。
C#浅拷贝和深拷贝数据-CSDN博客
本篇说一下,深拷贝的效率问题,效率一直是程序追求的,效率越高肯定越好,有时候功能是实现了,但是运行以及处理数据的效率非常低,此时就让人很头疼,当你知道了如何提高效率的时候,在你实现功能的时候,就已经考虑进去了,而不是先把功能做好,后期再优化(当然这种模式覆盖大部分人的开发习惯)。
测试1:
使用共同的数据结构和100W数量,分别对比4种深拷贝的效率问题。
1.反射
耗时:3465
2.JSON字符串序列化
耗时: 7095
3.表达式树
耗时:396
4.AutoMapper
耗时:682
结论:
表达式树>AutoMapper>反射>JSON。如果数据结构非常复杂而且多,那么就使用表达式树。
测试2:
使用共同的数据结构和10W数量,分别对比4种深拷贝的效率问题。
1.反射
耗时:498
2.JSON字符串序列化
耗时: 1072
3.表达式树
耗时:243
4.AutoMapper
耗时:268
结论:
表达式树>AutoMapper>反射>JSON
代码:
using AutoMapper;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using static WpfApp4.MainWindow;
using Expression = System.Linq.Expressions.Expression;namespace WpfApp4
{/// <summary>/// Interaction logic for MainWindow.xaml/// </summary>public partial class MainWindow : Window{public MainWindow(){InitializeComponent();Stopwatch sw = new Stopwatch();sw.Start();var config = new MapperConfiguration(cfg => cfg.CreateMap<TestData1, TestData1>());//映射配置for (int i = 0; i < 10_0000; i++){TestData3 testData3 = new TestData3();testData3.ID = 3 + i;testData3.D1 = "3.1" + i.ToString();testData3.D2 = "3.2" + i.ToString();TestData2 testData2 = new TestData2();testData2.ID = 2 + i;testData2.D1 = "2.1" + i.ToString();testData2.D2 = "2.2" + i.ToString();testData2.testData3 = testData3;TestData1 testData1 = new TestData1();testData1.ID = 1 + i;testData1.D1 = "1.1" + i.ToString();testData1.D2 = "1.2" + i.ToString();testData1.testData2 = testData2;//反射效率//var test2 = DeepCopyWithReflection(testData1);//JSON字符串序列化效率//var test3 = JsonConvert.DeserializeObject<TestData1>(JsonConvert.SerializeObject(testData1));//表达式树效率//var test4 = TransExp<TestData1, TestData1>.Trans(testData1);//AutoMapper效率var test5 = config.CreateMapper().Map<TestData1>(testData1);}double count = sw.Elapsed.TotalMilliseconds;sw.Stop();int a = 0;}/// <summary>/// 利用反射实现深拷贝/// </summary>/// <typeparam name="T"></typeparam>/// <param name="obj"></param>/// <returns></returns>public static T DeepCopyWithReflection<T>(T obj){Type type = obj.GetType();// 如果是字符串或值类型则直接返回if (obj is string || type.IsValueType) return obj;// 如果是数组if (type.IsArray){Type elementType = Type.GetType(type.FullName.Replace("[]", string.Empty));var array = obj as Array;Array copied = Array.CreateInstance(elementType, array.Length);for (int i = 0; i < array.Length; i++){copied.SetValue(DeepCopyWithReflection(array.GetValue(i)), i);}return (T)Convert.ChangeType(copied, obj.GetType());}object retval = Activator.CreateInstance(obj.GetType());PropertyInfo[] properties = obj.GetType().GetProperties(BindingFlags.Public | BindingFlags.NonPublic| BindingFlags.Instance | BindingFlags.Static);foreach (var property in properties){var propertyValue = property.GetValue(obj, null);if (propertyValue == null)continue;property.SetValue(retval, DeepCopyWithReflection(propertyValue), null);}return (T)retval;}/// <summary>/// 表达式树/// </summary>/// <typeparam name="TIn"></typeparam>/// <typeparam name="TOut"></typeparam>public static class TransExp<TIn, TOut>{private static readonly Func<TIn, TOut> cache = GetFunc();private static Func<TIn, TOut> GetFunc(){ParameterExpression parameterExpression = Expression.Parameter(typeof(TIn), "p");List<MemberBinding> memberBindingList = new List<MemberBinding>();foreach (var item in typeof(TOut).GetProperties()){if (!item.CanWrite) continue;MemberExpression property = Expression.Property(parameterExpression, typeof(TIn).GetProperty(item.Name));MemberBinding memberBinding = Expression.Bind(item, property);memberBindingList.Add(memberBinding);}MemberInitExpression memberInitExpression = Expression.MemberInit(Expression.New(typeof(TOut)), memberBindingList.ToArray());Expression<Func<TIn, TOut>> lambda = Expression.Lambda<Func<TIn, TOut>>(memberInitExpression, new ParameterExpression[] { parameterExpression });return lambda.Compile();}public static TOut Trans(TIn tIn){return cache(tIn);}}}
}
总结:总的来说,数据量在100W的时候,差距还是很明显的,建议使用表达式树,在10W数量的时候,表达式树和AutoMapper差距已经不是很大了,数据量再小的话,预计差别就更少了,具体使用,还是看程序的数据在什么量级。
源码:
https://download.csdn.net/download/u012563853/88637623
本文来源:
C#深拷贝效率对比-CSDN博客