ToB企服应用市场:ToB评测及商务社交产业平台

标题: 解读 --- 深拷贝 [打印本页]

作者: 西河刘卡车医    时间: 2023-8-14 01:19
标题: 解读 --- 深拷贝
引言

深拷贝是指创建一个新对象,该对象的值与原始对象完全相同,但在内存中具有不同的地址。这意味着如果您对原始对象进行更改,则不会影响到复制的对象
常见的C#常见的深拷贝方式有以下4类:
序列化、反序列化

使用二进制序列化和反序列化

可以使用 BinaryFormatter 类将对象序列化成二进制形式并保存到文件或内存流中,然后再使用 BinaryFormatter 反序列化对象,这样就可以得到该对象的一个完全独立的副本。
  1. using System.IO;
  2. using System.Runtime.Serialization.Formatters.Binary;
  3. public static T DeepCopy<T>(T obj)
  4. {
  5.     if (obj == null)
  6.     {
  7.         return default(T);
  8.     }
  9.     MemoryStream stream = new MemoryStream();
  10.     BinaryFormatter formatter = new BinaryFormatter();
  11.     formatter.Serialize(stream, obj);
  12.     stream.Seek(0, SeekOrigin.Begin);
  13.     T copy = (T)formatter.Deserialize(stream);
  14.     stream.Close();
  15.     return copy;
  16. }
复制代码
使用 XML 序列化和反序列化

可以使用 XmlSerializer 类将对象序列化成 XML 形式并保存到文件或内存流中,然后再使用 XmlSerializer 反序列化对象,这样也可以得到该对象的一个完全独立的副本。
  1. using System.IO;
  2. using System.Xml.Serialization;
  3. public static T DeepCopy<T>(T obj)
  4. {
  5.     if (obj == null)
  6.     {
  7.         return default(T);
  8.     }
  9.     XmlSerializer serializer = new XmlSerializer(typeof(T));
  10.     MemoryStream stream = new MemoryStream();
  11.     serializer.Serialize(stream, obj);
  12.     stream.Seek(0, SeekOrigin.Begin);
  13.     T copy = (T)serializer.Deserialize(stream);
  14.     stream.Close();
  15.     return copy;
  16. }
复制代码
使用 DataContractSerializer 序列化和反序列化

可以使用 DataContractSerializer 类将对象序列化成 XML 或二进制形式并保存到文件或内存流中,然后再使用 DataContractSerializer 反序列化对象。
  1. using System.IO;
  2. using System.Runtime.Serialization;
  3. using System.Runtime.Serialization.Json;
  4. using System.Runtime.Serialization.Formatters.Binary;
  5. public static T DeepCopy<T>(T obj)
  6. {
  7.     if (obj == null)
  8.     {
  9.         return default(T);
  10.     }
  11.     DataContractSerializer serializer = new DataContractSerializer(typeof(T));
  12.     MemoryStream stream = new MemoryStream();
  13.     serializer.WriteObject(stream, obj);
  14.     stream.Seek(0, SeekOrigin.Begin);
  15.     T copy = (T)serializer.ReadObject(stream);
  16.     stream.Close();
  17.     return copy;
  18. }
复制代码
使用 Json.NET 或 System.Text.Json 序列化和反序列化

可以使用 JsonConvert 类将对象序列化成 JSON 字符串,然后再使用 JsonConvert 反序列化对象。
  1. using Newtonsoft.Json;
  2. public static T DeepCopy<T>(T obj)
  3. {
  4.     if (obj == null)
  5.     {
  6.         return default(T);
  7.     }
  8.     string json = JsonConvert.SerializeObject(obj);
  9.     T copy = JsonConvert.DeserializeObject<T>(json);
  10.     return copy;
  11. }
复制代码
  1. using System.Text.Json;
  2. public static T DeepCopy<T>(T obj)
  3. {
  4.     if (obj == null)
  5.     {
  6.         return default(T);
  7.     }
  8.     string jsonString = JsonSerializer.Serialize<T>(obj);
  9.     // 将 JSON 字符串反序列化为对象
  10.     var deserializedPerson = JsonSerializer.Deserialize<T>(jsonString);
  11.     return deserializedPerson;
  12. }
复制代码
反射

使用反射实现深拷贝

通过反射生成对象,通过反射机制获取该对象的所有字段和属性信息。遍历所有字段和属性,以递归方式将源对象中的值复制到目标对象中。
  1. using System;
  2. using System.Reflection;
  3. public static T DeepCopy<T>(T obj)
  4. {
  5.     if (obj == null)
  6.     {
  7.         return default(T);
  8.     }
  9.     Type type = obj.GetType();
  10.     object copy = Activator.CreateInstance(type);
  11.     // 获取所有字段和属性信息,并将源对象中的值复制到目标对象中
  12.     foreach (FieldInfo fieldInfo in type.GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public))
  13.     {
  14.         object value = fieldInfo.GetValue(obj);
  15.         fieldInfo.SetValue(copy, DeepCopy(value));
  16.     }
  17.     foreach (PropertyInfo propertyInfo in type.GetProperties(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public))
  18.     {
  19.         if (!propertyInfo.CanWrite || !propertyInfo.CanRead)
  20.         {
  21.             continue;
  22.         }
  23.         object value = propertyInfo.GetValue(obj);
  24.         propertyInfo.SetValue(copy, DeepCopy(value));
  25.     }
  26.     return (T)copy;
  27. }
复制代码
手动赋值

手动复制所有成员变量

可以手动编写代码复制对象中的所有成员变量,这需要对对象结构有很好的了解,并且比较繁琐,容易漏掉某些成员。
  1. public class Person
  2. {
  3.     public string Name;
  4.     public int Age;
  5.     public Person DeepCopy()
  6.     {
  7.         Person copy = new Person();
  8.         copy.Name = this.Name;
  9.         copy.Age = this.Age;
  10.         return copy;
  11.     }
  12. }
复制代码
ICloneable 接口

实现 ICloneable 接口

可以在对象中实现 ICloneable 接口,并重写 Clone 方法来实现深拷贝。重写的 Clone 方法内可以调用上述任何一种方案。
  1. public class Person : ICloneable
  2. {
  3.     public string Name;
  4.     public int Age;
  5.     public object Clone()
  6.     {
  7.         Person copy = new Person();
  8.         copy.Name = this.Name;
  9.         copy.Age = this.Age;
  10.         return copy;
  11.     }
  12. }
复制代码
第三方库

还有一种方式是使用第三方库实现深拷贝,例如 AutoMapper、ValueInjecter 等。这些库可以自动复制对象中的所有成员变量,从而实现深拷贝。
其中比较常用的包括:
可以需要根据自己的具体需求选择适合自己的库。如果只是需要简单的深拷贝操作,那么 AutoMapper 和 Newtonsoft.Json 都是不错的选择;如果需要更加高效、灵活的操作,那么可以考虑使用 FastDeepCloner 或 Cloneable 等库。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4