C# 浅拷贝和深拷贝
浅拷贝:只复制对象的基本类型、对象类型、仍然属于原引用,也称为影子克隆;
深拷贝:不止复制对象的基本类,同时也复制原对象中的对象,完全就是新对象产生的,也称为深度克隆;
浅拷贝示例
类型基类System.Object已经为所有类型都实现了浅拷贝,类型所要做的就是公开一个复制的接口,而通常的,这个接口会借由实现ICloneable接口来实现。ICLoneable只包含一个Clone方法。该方法既可以被实现为浅拷贝也可以被实现为深拷贝,具体如何取舍需要根据具体类型的需求来决定。下面的代码提供了一个深拷贝的简单示例:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CloneTest
{
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
public Address Address { get; set; }
public Person Clone()
{
return (Person)this.MemberwiseClone();
}
}
public class Address
{
public string Province { get; set; }
public string City { get; set; }
}
}
namespace CloneTest
{
internal class Program
{
private static void Main(string[] args)
{
Person person = new Person();
person.Name = "Test";
person.Age = 30;
person.Address = new Address() { Province = "GD", City = "PN" };
Person shadow = person.Clone();
shadow.Name = "Test1";
shadow.Address.Province = "GX";
Console.WriteLine($"person.Name: {person.Name}");
Console.WriteLine($"shadow.Name: {shadow.Name}");
Console.WriteLine($"person.Province: {person.Address.Province}");
Console.WriteLine($"shadow.Province: {shadow.Address.Province}");
}
}
}
以上代码的执行结果如下
我们可以看的引用类型的属性Address一修改,两个类实例都跟着变化了
深拷贝示例
深拷贝是指复制对象的所有数据,包括对象内部引用的其他对象。这意味着,新的对象和原始对象不共享任何数据,它们是完全独立的。可以通过以下方式实现
1.反射的方式实现
public static T DeepCopy<T>(T obj)
{
//如果是字符串或值类型则直接返回
if (obj is string || obj.GetType().IsValueType)
{
return obj;
}
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, DeepCopyByFS(field.GetValue(obj)));
}
catch
{
}
}
return (T)retval;
}
2.二进制序列化方式实现
public static T DeepCopy<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;
}
使用该方式进行序列化,需要在对应的类上添加[Serializable]特性的
3.使用Newtonsoft.Json进行序列化和反序列化
public static T DeepCopyByNJ<T>(T obj)
{
if (obj == null)
{
return default(T);
}
T object2 = Newtonsoft.Json.JsonConvert.DeserializeObject<T>(Newtonsoft.Json.JsonConvert.SerializeObject(obj));
return object2;
}
需要Nuget安装包Newtonsoft.Json
以上的运行结果均为
区别
浅拷贝:是指将对象中的数值类型的字段拷贝到新的对象中,而对象中的引用类型的字段则指复制它的一个引用到目标对象。如果改变目标对象中引用型字段的值它将反应在原始对象中,也就是说原始对象中对应的字段也会发生变化。
深拷贝:与浅拷贝的不同是对于引用的处理,深拷贝将会在内存中创建一个新的对象,对应字段和原始对象完全相同。也就是说这个引用和原始对象的引用是不相同的,因为新对象与原对象引用地址不同,我们在改变新对象中的这个字段的时候是不会影响到原始字段中对应字段的内容。