.NET 中的浅拷贝 vs 深拷贝






3.25/5 (50投票s)
浅拷贝和深拷贝用于在对象之间复制数据。
引言
本文使用 C# 描述了浅拷贝和深拷贝的区别。 浅拷贝和深拷贝用于在对象之间复制数据。
浅拷贝
浅拷贝是创建一个新对象,然后将当前对象的非静态字段复制到新对象中。如果字段是值类型 --> 将执行字段的逐位复制;对于引用类型 --> 复制引用,但不复制引用的对象;因此,原始对象及其克隆都引用同一个对象。
在 C# 和 VB.NET 中,浅拷贝是通过对象方法 MemberwiseClone()
完成的。
示例:以下 clsShallow
类将被克隆,其中包括值类型(如 Age
)和引用类型(如 EmpSalary
是一个类)
public class clsShallow
{
public static string CompanyName = "My Company";
public int Age;
public string EmployeeName;
public clsRefSalary EmpSalary;
public clsShallow CreateShallowCopy(clsShallow inputcls)
{
return (clsShallow)inputcls.MemberwiseClone();
}
}
public class clsRefSalary
{
public clsRefSalary(int _salary)
{
Salary = _salary;
}
public int Salary;
}
现在让我们调试并跟踪输出,使用 CreateShallowCopy()
方法进行浅拷贝。
首先,使用以下代码从其他类调用 CreateShallowCopy
方法。
// Creates an instance of clsShallow and assign values to its fields.
clsShallow objshallow = new clsShallow();
objshallow.Age = 25;
objshallow.EmployeeName = "Ahmed Eid";
// add the ref value to the objshallow
clsRefSalary clsref = new clsRefSalary(1000);
objshallow.EmpSalary = clsref;
// Performs a shallow copy of m1 and assign it to m2.
clsShallow m2 = objshallow.CreateShallowCopy(objshallow);
// then modify the clsref salary value to be 2000
clsref.Salary = 2000;
// so the m1 object salary value become 2000
int EmpSalary = objshallow.EmpSalary.Salary;
将值(值类型和引用类型)分配给对象 objShallow
并且在进行浅拷贝之前,这些值是(对于当前对象值):Age
:25(值类型),EmpSalry
:工资值为 1000(引用类型)。
然后进行浅拷贝并修改 clsref.salary
的值,即引用字段类型,然后再次检查 m2 的值,即新创建的对象 (引用和值字段)。
这些值是(对于新创建的对象):Age
:25(值类型),是 objShallow
对象的一个新副本;EmpSalry
:工资值为 2000(引用类型),是对 objShallow.EmpSalry
对象的引用,也引用了 clsref
对象。
注意:修改 clsref
值(引用类型概念)后,m2.EmpSalry
和 clsref
的值相同。
深拷贝
深拷贝是创建一个新对象,然后将当前对象的非静态字段复制到新对象。如果字段是值类型 --> 将执行字段的逐位复制。如果字段是引用类型 --> 将执行所引用对象的新副本。
注意:要克隆的类必须标记为 [Serializable]
。
示例:以下是将被克隆的 clsDeep
类,其中包括值类型(如 Age
)和引用类型(如 EmpSalary
,它是一个类)。
[Serializable]
// serialize the classes in case of deep copy
public class clsDeep
{
public static string CompanyName = "My Company";
public int Age;
public string EmployeeName;
public clsRefSalary EmpSalary;
public clsDeep CreateDeepCopy(clsDeep inputcls)
{
MemoryStream m = new MemoryStream();
BinaryFormatter b = new BinaryFormatter();
b.Serialize(m, inputcls);
m.Position = 0;
return (clsDeep)b.Deserialize(m);
}
}
[Serializable]
public class clsRefSalary
{
public clsRefSalary(int _salary)
{
Salary = _salary;
}
public int Salary;
}
现在让我们调试并跟踪输出,使用 CreateDeepCopy()
方法进行深拷贝。
首先,使用以下代码从其他类调用 CreateDeepCopy
方法。
// Creates an instance of clsDeep and assign values to its fields.
clsDeep objdeep = new clsDeep();
objdeep.Age = 25;
objdeep.EmployeeName = "Ahmed Eid";
// add the ref value
clsRefSalary clsref = new clsRefSalary(1000);
objdeep.EmpSalary = clsref;
// Performs a shallow copy of m1 and assign it to m2.
clsDeep m2 = objdeep.CreateDeepCopy(objdeep);
// then modify the clsref salary value to be 2000
clsref.Salary = 2000;
// so the m1 object salary value become 2000
int EmpSalary = objdeep.EmpSalary.Salary;
将值(值类型和引用类型)分配给对象 objDeep
并且在进行深拷贝之前,这些值是(对于当前对象值):Age
:25(值类型);EmpSalry
:工资值为 1000(引用类型)。
然后进行深拷贝并修改 clsref.salary
的值,即引用字段类型,然后再次检查 m2
的值,即新创建的对象(引用和值字段)。
这些值是(对于新创建的对象):Age
:25(值类型),是 objDeep
对象的一个新副本;EmpSalry
:工资值为 1000,是 objDeep
对象的一个新副本。
注意:m2.EmpSalry
和 objDeep.EmpSalary
的值不一样,因为深拷贝会在 m2.EmpSalry
中创建引用类型(objDeep.EmpSalary
)的新对象。但是,clsref
和 objDeep.EmpSalary
是相同的(引用类型概念)。
在 Google 的帮助下,我找到了一种非常智能的方法来执行深拷贝。它的性能比我上面使用的那个方法要好。
/// <summary>
/// Using generics will solve some performance issues
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="item"></param>
/// <returns></returns>
public static T DeepCopy<T>(T item)
{
BinaryFormatter formatter = new BinaryFormatter();
MemoryStream stream = new MemoryStream();
formatter.Serialize(stream, item);
stream.Seek(0, SeekOrigin.Begin);
T result = (T)formatter.Deserialize(stream);
stream.Close();
return result;
}
您可以在以下网址找到该文章:http://ahmadeed.blogspot.com。
我希望本文能帮助您深入了解 .NET 中浅拷贝和深拷贝的区别。