65.9K
CodeProject 正在变化。 阅读更多。
Home

.NET 中的浅拷贝 vs 深拷贝

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.25/5 (50投票s)

2008年8月30日

CPOL

3分钟阅读

viewsIcon

260572

downloadIcon

1156

浅拷贝和深拷贝用于在对象之间复制数据。

引言

本文使用 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(引用类型)。

shal1

然后进行浅拷贝并修改 clsref.salary 的值,即引用字段类型,然后再次检查 m2 的值,即新创建的对象 (引用和值字段)。

shal1

这些值是(对于新创建的对象):Age:25(值类型),是 objShallow 对象的一个新副本;EmpSalry:工资值为 2000(引用类型),是对 objShallow.EmpSalry 对象的引用,也引用了 clsref 对象。

注意:修改 clsref 值(引用类型概念)后,m2.EmpSalryclsref 的值相同。

深拷贝

深拷贝是创建一个新对象,然后将当前对象的非静态字段复制到新对象。如果字段是值类型 --> 将执行字段的逐位复制。如果字段是引用类型 --> 将执行所引用对象的新副本。

注意:要克隆的类必须标记为 [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(引用类型)。

deep1

然后进行深拷贝并修改 clsref.salary 的值,即引用字段类型,然后再次检查 m2 的值,即新创建的对象(引用和值字段)。

deep1

这些值是(对于新创建的对象):Age:25(值类型),是 objDeep 对象的一个新副本;EmpSalry:工资值为 1000,是 objDeep 对象的一个新副本。

注意:m2.EmpSalryobjDeep.EmpSalary 的值不一样,因为深拷贝会在 m2.EmpSalry 中创建引用类型(objDeep.EmpSalary)的新对象。但是,clsrefobjDeep.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 中浅拷贝和深拷贝的区别。

© . All rights reserved.