对于浅拷贝和深拷贝,前面的文章已经说明了。
? ? ? ? 本篇说一下,深拷贝的效率问题,效率一直是程序追求的,效率越高肯定越好,有时候功能是实现了,但是运行以及处理数据的效率非常低,此时就让人很头疼,当你知道了如何提高效率的时候,在你实现功能的时候,就已经考虑进去了,而不是先把功能做好,后期再优化(当然这种模式覆盖大部分人的开发习惯)。
测试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
本文来源: