佳佳的博客
Menu
首页
C# 深拷贝方法效率比较(2)
Posted by
佳佳
on 2020-05-13
IT
C#
在 [之前的博客][1] 中比较了两种深拷贝的性能,但是最近发现通过反射深拷贝的 *DeepCopyByReflect* 方法虽然效率高,但是在遇到数组/列表类型的字段时会报错。 添加了其对数组/列表类型的支持后,测试代码更新如下。 另外新增了一个通过序列化为 *JSON* 字符串,然后再反序列化的方法。使用了 *Newtonsoft.Json* 包。 ```csharp using Newtonsoft.Json; using System; using System.Diagnostics; using System.Linq; using System.IO; using System.Reflection; using System.Runtime.Serialization.Formatters.Binary; using System.Collections.Generic; namespace CloneCompare { class Program { static void Main(string[] args) { int loop = 10 * 10000; var staff = new Staff() { FirstName = "佳佳", LastName = "刘", Site = "liujiajia.me", History = new string[] { "A University", "A Company" }, Scores = new List<Score> { new Score() { Course = "语文", Point = 80 }, new Score() { Course = "数学", Point = 85 }, } }; Stopwatch sw1 = new Stopwatch(); sw1.Start(); for (int i = 0; i < loop; i++) { _ = DeepCopyByReflect(staff); } sw1.Stop(); Console.WriteLine($"通过 DeepCopyByReflect 方法创建深拷贝耗费 {sw1.ElapsedMilliseconds} ms"); sw1.Reset(); sw1.Start(); for (int i = 0; i < loop; i++) { _ = DeepCopyByBin(staff); } sw1.Stop(); Console.WriteLine($"通过 DeepCopyByBin 方法创建深拷贝耗费 {sw1.ElapsedMilliseconds} ms"); sw1.Reset(); sw1.Start(); for (int i = 0; i < loop; i++) { _ = DeepCopyByJSON(staff); } sw1.Stop(); Console.WriteLine($"通过 DeepCopyByJSON 方法创建深拷贝耗费 {sw1.ElapsedMilliseconds} ms"); Console.ReadLine(); } /// <summary> /// 深拷贝,通过序列化与反序列化实现 /// </summary> /// <typeparam name="T">深拷贝的类类型</typeparam> /// <param name="obj">深拷贝的类对象</param> /// <returns></returns> public static T DeepCopyByBin<T>(T obj) { object retval; using (MemoryStream ms = new MemoryStream()) { BinaryFormatter bf = new BinaryFormatter(); //序列化成流 bf.Serialize(ms, obj); ms.Seek(0, SeekOrigin.Begin); //反序列化成对象 retval = bf.Deserialize(ms); ms.Close(); } return (T)retval; } /// <summary> /// 深拷贝,通过JOSN实现 /// </summary> /// <typeparam name="T">深拷贝的类类型</typeparam> /// <param name="obj">深拷贝的类对象</param> /// <returns></returns> public static T DeepCopyByJSON<T>(T obj) { return JsonConvert.DeserializeObject<T>(JsonConvert.SerializeObject(obj)); } /// <summary> /// 深拷贝,通过反射实现 /// </summary> /// <typeparam name="T">深拷贝的类类型</typeparam> /// <param name="obj">深拷贝的类对象</param> /// <returns></returns> public static T DeepCopyByReflect<T>(T obj) { // 如果是字符串或值类型则直接返回 if (obj is string || obj.GetType().IsValueType) return obj; // 如果是数组类型 if (obj.GetType().IsArray) { var array = obj as Array; var newArray = Array.CreateInstance(array.GetType().GetElementType(), array.Length); for (int i = 0; i < array.Length; i++) { newArray.SetValue(DeepCopyByReflect(array.GetValue(i)), i); } return (T)(object)newArray; } if (obj.GetType().FullName.IndexOf("System.Collections.Generic.List") == 0) { var list = Activator.CreateInstance(obj.GetType()); int count = Convert.ToInt32(obj.GetType().GetProperty("Count").GetValue(obj)); for (int i = 0; i < count; i++) { obj.GetType().GetMethod("Add").Invoke(list, new object[] { DeepCopyByReflect(obj.GetType().GetProperty("Item").GetValue(obj, new object[] { i })) }); } return (T)list; } object retval = Activator.CreateInstance(obj.GetType()); FieldInfo[] fields = obj.GetType().GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static); foreach (FieldInfo field in fields) { try { field.SetValue(retval, DeepCopyByReflect(field.GetValue(obj))); } catch (Exception ex) { Console.WriteLine(ex); } } return (T)retval; } /// <summary> /// 深拷贝,通过反射实现 /// </summary> /// <typeparam name="T">深拷贝的类类型</typeparam> /// <param name="obj">深拷贝的类对象</param> /// <returns></returns> public static List<T> DeepCopyByReflect<T>(List<T> obj) { return obj.Select(m => DeepCopyByReflect(m)).ToList(); } } [Serializable] class Staff { public string FirstName { get; set; } public string LastName { get; set; } public string Site { get; set; } public string[] History { get; set; } public List<Score> Scores { get; set; } } [Serializable] public class Score { public string Course { get; set; } public int Point { get; set; } } } ``` 执行结果如下: > 通过 DeepCopyByReflect 方法创建深拷贝耗费 755 ms > 通过 DeepCopyByBin 方法创建深拷贝耗费 3645 ms > 通过 DeepCopyByJSON 方法创建深拷贝耗费 1195 ms 可以看到通过反射的实现(*DeepCopyByReflect*)耗时增加了好多,但仍然是效率最高的。 通过 *JSON* 序列化/反序列化的实现效率跟反射相比差距不大,实现起来比较简单,而且 *Newtonsoft.Json* 包使用的人也很多,健壮性比较高。性能要求不是很苛刻的地方,推荐使用这种方法。 [1]: /2019/11/15/compare-performance-of-two-deep-copy-methods-in-csharp (C# 两种深拷贝方法效率比较)
版权声明:原创文章,未经允许不得转载。
https://www.liujiajia.me/2020/5/13/compare-performance-of-two-deep-copy-methods-in-csharp-2
“Buy me a nongfu spring”
« [SqlServer] geography 空间类型数据
《重构》 7. 封装 »
昵称
*
电子邮箱
*
回复内容
*
(回复审核后才会显示)
提交
目录
AUTHOR
刘佳佳
江苏 - 苏州
软件工程师