• 理解C#中对象的浅拷贝和深拷贝


    本文章主要介绍C#中对象的拷贝,其中包括浅拷贝和深拷贝,以及浅拷贝和深拷贝的实现方式,不同的实现方式之间的性能对比。

     

    1、浅拷贝和深拷贝

    浅拷贝是指将对象中的数值类型的字段拷贝到新的对象中,而对象中的引用型字段则指复制它的一个引用到目标对象。如果改变目标对象中引用型字段的值他将反映在原是对象中,也就是说原始对象中对应的字段也会发生变化。深拷贝与浅拷贝不同的是对于引用的处理,深拷贝将会在新对象中创建一个新的和原是对象中对应字段相同(内容相同)的字段,也就是说这个引用和原是对象的引用是不同的,我们在改变新对象中的这个字段的时候是不会影响到原始对象中对应字段的内容。

    2、浅拷贝实现方式

    1)new对象赋值

    1. [Serializable]
    2. class Employee
    3. {
    4. public string ID { get; set; }
    5. public int Age { get; set; }
    6. public Department DepartmentName { get; set; }
    7. }
    8. [Serializable]
    9. class Department
    10. {
    11. public string DepartmentName { get; set; }
    12. public Department(string value)
    13. {
    14. DepartmentName = value;
    15. }
    16. public override string ToString()
    17. {
    18. return DepartmentName.ToString();
    19. }
    20. }
    21. Employee emp1 = new Employee()
    22. {
    23. ID = "cjavapy",
    24. Age = 20,
    25. DepartmentName = new Department("develop")
    26. }
    27. ;
    28. Employee emp2=new Employee()
    29. {
    30. ID=emp1.ID,
    31. Age=emp1.Age,
    32. DepartmentName=emp1.DepartmentName
    33. };

     2)实现ICloneable接口

    1. class Employee : ICloneable
    2. {
    3. public string ID { get; set; }
    4. public int Age { get; set; }
    5. public Department DepartmentName { get; set; }
    6. //实现ICloneable接口的Clone方法
    7. public object Clone()
    8. {
    9. return this.MemberwiseClone();//浅拷贝
    10. }
    11. }
    12. class Department
    13. {
    14. public string DepartmentName { get; set; }
    15. public Department(string value)
    16. {
    17. DepartmentName = value;
    18. }
    19. public override string ToString()
    20. {
    21. return DepartmentName.ToString();
    22. }
    23. }

     浅拷贝:

    1. Employee emp1 = new Employee()
    2. {
    3. ID = "cjavapy",
    4. Age = 20,
    5. DepartmentName = new Department("develop")
    6. };
    7. Employee emp2 = emp1.Clone() as Employee;//浅拷贝

     

    3、深拷贝实现方式

    1)二进制序列化

    1. using System;
    2. using System.Collections.Generic;
    3. using System.IO;
    4. using System.Runtime.Serialization;
    5. using System.Runtime.Serialization.Formatters.Binary;
    6. using System.Xml.Serialization;
    7. using Newtonsoft.Json;
    8. namespace ConsoleApplication
    9. {
    10. public class Utils
    11. {
    12. public static T BinaryClone<T>(T source)
    13. {
    14. if (!typeof(T).IsSerializable)
    15. {
    16. throw new ArgumentException("需要添加[Serializable]标签", "source");
    17. }
    18. if (Object.ReferenceEquals(source, null))
    19. {
    20. return default(T);
    21. }
    22. IFormatter formatter = new BinaryFormatter();
    23. Stream stream = new MemoryStream();
    24. using (stream)
    25. {
    26. formatter.Serialize(stream, source);
    27. stream.Seek(0, SeekOrigin.Begin);
    28. return (T)formatter.Deserialize(stream);
    29. }
    30. }
    31. }
    32. }

     2)JSON序列化

    1. using System.Collections.Generic;
    2. using System.IO;
    3. using System.Xml.Serialization;
    4. using Newtonsoft.Json;
    5. namespace ConsoleApplication
    6. {
    7. public class Utils
    8. {
    9. ///
    10. /// 序列化反序列化方式
    11. ///
    12. ///
    13. ///
    14. public static TOut JsonClone<TIn,TOut>(TIn tIn)
    15. {
    16. return JsonConvert.DeserializeObject<TOut>(JsonConvert.SerializeObject(tIn));
    17. }
    18. }
    19. }

     3)Reflection反射

    1. using System;
    2. using System.Collections.Generic;
    3. using System.Linq;
    4. using System.Text;
    5. using System.Threading.Tasks;
    6. namespace ConsoleApplication
    7. {
    8. public class Utils
    9. {
    10. ///
    11. /// 反射实现深拷贝
    12. ///
    13. /// 传入TIn对象返回TOut对象
    14. ///
    15. public static TOut ReflectionClone<TIn, TOut>(TIn tIn)
    16. {
    17. TOut tOut = Activator.CreateInstance<TOut>();
    18. foreach (var itemOut in tOut.GetType().GetProperties())
    19. {
    20. var propIn = tIn.GetType().GetProperty(itemOut.Name);
    21. itemOut.SetValue(tOut, propIn.GetValue(tIn));
    22. }
    23. foreach (var itemOut in tOut.GetType().GetFields())
    24. {
    25. var fieldIn = tIn.GetType().GetField(itemOut.Name);
    26. itemOut.SetValue(tOut, fieldIn.GetValue(tIn));
    27. }
    28. return tOut;
    29. }
    30. /// <summary>
    31. /// 传入List<TIn>,返回List<TOut>
    32. /// </summary>
    33. /// <typeparam name="TIn"></typeparam>
    34. /// <typeparam name="TOut"></typeparam>
    35. /// <param name="tInList"></param>
    36. /// <returns></returns>
    37. public static List<TOut> ReflectionCloneList<TIn, TOut>(List<TIn> tInList)
    38. {
    39. List<TOut> result = new List<TOut>();
    40. foreach (var tIn in tInList)
    41. {
    42. TOut tOut = Activator.CreateInstance<TOut>();
    43. foreach (var itemOut in tOut.GetType().GetProperties())
    44. {
    45. var propIn = tIn.GetType().GetProperty(itemOut.Name);
    46. itemOut.SetValue(tOut, propIn.GetValue(tIn));
    47. }
    48. foreach (var itemOut in tOut.GetType().GetFields())
    49. {
    50. var fieldIn = tIn.GetType().GetField(itemOut.Name);
    51. itemOut.SetValue(tOut, fieldIn.GetValue(tIn));
    52. }
    53. result.Add(tOut);
    54. }
    55. return result;
    56. }
    57. }
    58. public class ContactPerson
    59. {
    60. public string Name { get; set; }
    61. public string MobileNum { get; set; }
    62. }
    63. class Program
    64. {
    65. static void Main(string[] args)
    66. {
    67. var persons = new List<ContactPerson>
    68. {
    69. new ContactPerson { Name= "C", MobileNum = "13756863001"},
    70. new ContactPerson { Name = "C#", MobileNum = "13756863002"},
    71. new ContactPerson { Name = "Java", MobileNum = "13756863003"}
    72. };
    73. var result = Utils.ReflectionCloneList<ContactPerson, ContactPerson>(persons);
    74. foreach(var p in result)
    75. Console.WriteLine("姓名: {0} 号码为: {1}", p.Name, p.MobileNum);
    76. Console.Read();
    77. }
    78. }
    79. }

     4)XML序列化

    1. using System.IO;
    2. using System.Xml.Serialization;
    3. namespace ConsoleApplication
    4. {
    5. public class Utils
    6. {
    7. public static T DeserializeXML<T>(string xmlData) where T : new()
    8. {
    9. if (string.IsNullOrEmpty(xmlData))
    10. return default(T);
    11. TextReader tr = new StringReader(xmlData);
    12. T DocItms = new T();
    13. XmlSerializer xms = new XmlSerializer(DocItms.GetType());
    14. DocItms = (T)xms.Deserialize(tr);
    15. return DocItms == null ? default(T) : DocItms;
    16. }
    17. }
    18. }

     5)表达式目录树

    1. using System;
    2. using System.Collections.Generic;
    3. using System.Linq;
    4. using System.Linq.Expressions;
    5. using System.Text;
    6. using System.Threading.Tasks;
    7. namespace ConsoleApplication
    8. {
    9. /// <summary>
    10. /// 生成表达式目录树 泛型缓存
    11. /// </summary>
    12. /// <typeparam name="TIn"></typeparam>
    13. /// <typeparam name="TOut"></typeparam>
    14. public class ExpressionGenericMapper<TIn, TOut>//`2
    15. {
    16. private static Func<TIn, TOut> _FUNC = null;
    17. static ExpressionGenericMapper()
    18. {
    19. ParameterExpression parameterExpression = Expression.Parameter(typeof(TIn), "p");
    20. List<MemberBinding> memberBindingList = new List<MemberBinding>();
    21. foreach (var item in typeof(TOut).GetProperties())
    22. {
    23. MemberExpression property = Expression.Property(parameterExpression, typeof(TIn).GetProperty(item.Name));
    24. MemberBinding memberBinding = Expression.Bind(item, property);
    25. memberBindingList.Add(memberBinding);
    26. }
    27. foreach (var item in typeof(TOut).GetFields())
    28. {
    29. MemberExpression property = Expression.Field(parameterExpression, typeof(TIn).GetField(item.Name));
    30. MemberBinding memberBinding = Expression.Bind(item, property);
    31. memberBindingList.Add(memberBinding);
    32. }
    33. MemberInitExpression memberInitExpression = Expression.MemberInit(Expression.New(typeof(TOut)), memberBindingList.ToArray());
    34. Expression<Func<TIn, TOut>> lambda = Expression.Lambda>(memberInitExpression, new ParameterExpression[]
    35. {
    36. parameterExpression
    37. });
    38. _FUNC = lambda.Compile();//
    39. }
    40. public static TOut Trans(TIn t)
    41. {
    42. return _FUNC(t);
    43. }
    44. }
    45. }

     

    4、拷贝方式性能对比

    对比代码:

    1. using System;
    2. using System.Collections.Generic;
    3. using System.Linq;
    4. using System.Linq.Expressions;
    5. using System.Text;
    6. using System.Threading.Tasks;
    7. using System.Diagnostics;
    8. using System.Xml.Serialization;
    9. using System.IO;
    10. using System.Runtime.Serialization;
    11. using System.Runtime.Serialization.Formatters.Binary;
    12. using Newtonsoft.Json;
    13. namespace ConsoleApplication
    14. {
    15. class Program
    16. {
    17. static void Main(string[] args)
    18. {
    19. Employee emp1 = new Employee()
    20. {
    21. ID = "cjavapy",
    22. Age = 20,
    23. DepartmentName = new Department("develop")
    24. };
    25. long common = 0;
    26. long expression = 0;
    27. long json = 0;
    28. long xml = 0;
    29. long binary = 0;
    30. long reflection = 0;
    31. {
    32. Stopwatch watch = new Stopwatch();
    33. watch.Start();
    34. for (int i = 0; i < 1000000; i++)
    35. {
    36. Employee copy = BinaryClone<Employee>(emp1);
    37. }
    38. watch.Stop();
    39. binary = watch.ElapsedMilliseconds;
    40. }
    41. {
    42. Stopwatch watch = new Stopwatch();
    43. watch.Start();
    44. for (int i = 0; i < 1000000; i++)
    45. {
    46. Employee copy = ReflectionClone<Employee, Employee>(emp1);
    47. }
    48. watch.Stop();
    49. reflection = watch.ElapsedMilliseconds;
    50. }
    51. {
    52. Stopwatch watch = new Stopwatch();
    53. watch.Start();
    54. for (int i = 0; i < 1000000; i++)
    55. {
    56. Employee copy = DeserializeXML<Employee>(SerializeXML<Employee>(emp1));
    57. }
    58. watch.Stop();
    59. xml = watch.ElapsedMilliseconds;
    60. }
    61. {
    62. Stopwatch watch = new Stopwatch();
    63. watch.Start();
    64. for (int i = 0; i < 1000000; i++)
    65. {
    66. Employee copy = JsonClone<Employee, Employee>(emp1);
    67. }
    68. watch.Stop();
    69. json = watch.ElapsedMilliseconds;
    70. }
    71. {
    72. Stopwatch watch = new Stopwatch();
    73. watch.Start();
    74. for (int i = 0; i < 1000000; i++)
    75. {
    76. Employee copy = ExpressionGeneric<Employee, Employee>.Clone(emp1);
    77. }
    78. watch.Stop();
    79. expression = watch.ElapsedMilliseconds;
    80. }
    81. Console.WriteLine($"binary = { binary} ms");
    82. Console.WriteLine($"reflection = { reflection} ms");
    83. Console.WriteLine($"serialize = { xml} ms");
    84. Console.WriteLine($"json = { json} ms");
    85. Console.WriteLine($"generic = { expression} ms");
    86. Console.ReadKey();
    87. }
    88. public static T BinaryClone<T>(T source)
    89. {
    90. if (!typeof(T).IsSerializable)
    91. {
    92. throw new ArgumentException("需要添加[Serializable]标签", "source");
    93. }
    94. if (Object.ReferenceEquals(source, null))
    95. {
    96. return default(T);
    97. }
    98. IFormatter formatter = new BinaryFormatter();
    99. Stream stream = new MemoryStream();
    100. using (stream)
    101. {
    102. formatter.Serialize(stream, source);
    103. stream.Seek(0, SeekOrigin.Begin);
    104. return (T)formatter.Deserialize(stream);
    105. }
    106. }
    107. /// <summary>
    108. /// 反射
    109. /// </summary>
    110. /// <typeparam name="TIn"></typeparam>
    111. /// <typeparam name="TOut"></typeparam>
    112. /// <param name="tIn"></param>
    113. /// <returns></returns>
    114. public static TOut ReflectionClone<TIn, TOut>(TIn tIn)
    115. {
    116. TOut tOut = Activator.CreateInstance<TOut>();
    117. foreach (var itemOut in tOut.GetType().GetProperties())
    118. {
    119. var propIn = tIn.GetType().GetProperty(itemOut.Name);
    120. itemOut.SetValue(tOut, propIn.GetValue(tIn));
    121. }
    122. foreach (var itemOut in tOut.GetType().GetFields())
    123. {
    124. var fieldIn = tIn.GetType().GetField(itemOut.Name);
    125. itemOut.SetValue(tOut, fieldIn.GetValue(tIn));
    126. }
    127. return tOut;
    128. }
    129. public static TOut JsonClone<TIn, TOut>(TIn tIn)
    130. {
    131. return JsonConvert.DeserializeObject<TOut>(JsonConvert.SerializeObject(tIn));
    132. }
    133. public static string SerializeXML<T>(T t)
    134. {
    135. using (StringWriter sw = new StringWriter())
    136. {
    137. XmlSerializer xz = new XmlSerializer(t.GetType());
    138. xz.Serialize(sw, t);
    139. return sw.ToString();
    140. }
    141. }
    142. public static T DeserializeXML<T>(string xmlData) where T : new()
    143. {
    144. if (string.IsNullOrEmpty(xmlData))
    145. return default(T);
    146. TextReader tr = new StringReader(xmlData);
    147. T DocItms = new T();
    148. XmlSerializer xms = new XmlSerializer(DocItms.GetType());
    149. DocItms = (T)xms.Deserialize(tr);
    150. return DocItms == null ? default(T) : DocItms;
    151. }
    152. }
    153. [Serializable]
    154. public class Employee : ICloneable
    155. {
    156. public string ID { get; set; }
    157. public int Age { get; set; }
    158. public Department DepartmentName { get; set; }
    159. //实现ICloneable接口的Clone方法
    160. public object Clone()
    161. {
    162. return this.MemberwiseClone();//浅拷贝
    163. }
    164. }
    165. [Serializable]
    166. public class Department
    167. {
    168. public string DepartmentName { get; set; }
    169. public Department()
    170. {
    171. }
    172. public Department(string value)
    173. {
    174. DepartmentName = value;
    175. }
    176. public override string ToString()
    177. {
    178. return DepartmentName.ToString();
    179. }
    180. }
    181. /// <typeparam name="TIn"></typeparam>
    182. /// <typeparam name="TOut"></typeparam>
    183. public class ExpressionGeneric<TIn, TOut>//Mapper`2
    184. {
    185. private static Func<TIn, TOut> _FUNC = null;
    186. static ExpressionGeneric()
    187. {
    188. ParameterExpression parameterExpression = Expression.Parameter(typeof(TIn), "p");
    189. List<MemberBinding> memberBindingList = new List<MemberBinding>();
    190. foreach (var item in typeof(TOut).GetProperties())
    191. {
    192. MemberExpression property = Expression.Property(parameterExpression, typeof(TIn).GetProperty(item.Name));
    193. MemberBinding memberBinding = Expression.Bind(item, property);
    194. memberBindingList.Add(memberBinding);
    195. }
    196. foreach (var item in typeof(TOut).GetFields())
    197. {
    198. MemberExpression property = Expression.Field(parameterExpression, typeof(TIn).GetField(item.Name));
    199. MemberBinding memberBinding = Expression.Bind(item, property);
    200. memberBindingList.Add(memberBinding);
    201. }
    202. MemberInitExpression memberInitExpression = Expression.MemberInit(Expression.New(typeof(TOut)), memberBindingList.ToArray());
    203. Expression<Func<TIn, TOut>> lambda = Expression.Lambda>(memberInitExpression, new ParameterExpression[]
    204. {
    205. parameterExpression
    206. });
    207. _FUNC = lambda.Compile();
    208. }
    209. public static TOut Clone(TIn t)
    210. {
    211. return _FUNC(t);
    212. }
    213. }
    214. }

     

  • 相关阅读:
    Mybatis-plus使用教程
    mulesoft Module 13 quiz 解析
    论文笔记: 极限多标签学习之 FastXML
    455. 分发饼干
    怒刷LeetCode的第3天(Java版)
    HTML常见标签和作用
    06_通信过程
    【vue3】04. 跟着官网学习vue3
    通用FIFO设计深度8宽度64,verilog仿真,源码和视频
    Java中的数据类型和运算符
  • 原文地址:https://blog.csdn.net/lwf3115841/article/details/134098449