在编程中,经常需要复制对象。有时,只是简单地让两个对象变量引用同一个对象,但有时需要两个独立的副本,以便在不影响原始对象的情况下修改数据。在.NET环境中,可以通过浅复制和深复制来实现这一需求。
浅复制创建一个新的对象,并将原始对象的每个成员赋值给新对象的对应成员。对于值类型的成员,这是一种真正的复制;但对于包含引用类型的成员,这并不会产生真正的复制。例如,字符串(string)是一种引用类型。当将一个字符串变量赋值给另一个字符串变量时,两个变量都会引用相同的字符串数据。字符串的字符并没有真正被复制。因此,如果一个类包含引用成员,浅复制并不会产生所有类成员的真正副本。
在许多情况下,浅复制是足够的。需要注意的是,字符串是不可变的,不能被改变。当创建一个包含字符串的浅复制对象,并在新对象中修改字符串时,这将创建一个新的字符串,并且不会对原始对象中的原始字符串产生任何影响。需要注意的是,其他数据类型,如数组、类对象以及类对象数组,可能会比字符串更复杂。
深复制是创建一个不包含任何原始数据的副本。每个成员的真正副本被创建。对于值类型成员,深复制不需要做任何特殊处理。但对于引用数据类型,新对象必须引用数据的副本,而不是原始数据。
在.NET中实现对象复制的方法并不复杂。下面是一个示例,展示了如何使用一个名为MyClass的类对象进行浅复制和深复制。
protected class MyClass
{
public int i;
public int j;
public string message;
}
private void Test()
{
MyClass mc1 = new MyClass();
mc1.i = 5;
mc1.j = 10;
mc1.message = "Hello, World!";
MyClass mc2 = new MyClass();
mc2.i = mc1.i;
mc2.j = mc1.j;
mc2.message = mc1.message;
}
在浅复制中,没有做任何特殊处理。只是将一个对象的每个成员赋值给另一个对象。对于值类型的成员,深复制使用相同的代码。然而,对于引用类型的成员,如字符串,代码必须创建字符串数据的副本。
protected class MyClass : ICloneable
{
public int i;
public int j;
public string message;
public object Clone()
{
MyClass mc = new MyClass();
mc.i = i;
mc.j = j;
if (message != null)
mc.message = String.Copy(message);
return mc;
}
}
private void Test()
{
MyClass mc1 = new MyClass();
mc1.i = 5;
mc1.j = 10;
mc1.message = "Hello, World!";
MyClass mc2 = (MyClass)mc1.Clone();
}
在深复制中,通过实现ICloneable接口并重写Clone方法来实现。这种方式的主要优点是它作为类的一部分实现,可以轻松地在应用程序的任何地方进行修改和调用。
.NET框架提供了一些工具来帮助执行这些任务。例如,可以使用MemberwiseClone方法来执行浅复制。
protected class MyClass : ICloneable
{
public int i;
public int j;
public string message;
public object Clone()
{
return MemberwiseClone();
}
}
private void Test()
{
MyClass mc1 = new MyClass();
mc1.i = 5;
mc1.j = 10;
mc1.message = "Hello, World!";
MyClass mc2 = (MyClass)mc1.Clone();
}
在这个示例中,使用MemberwiseClone方法来执行浅复制。MemberwiseClone方法是受保护的,因此不能直接从Test方法中调用。相反,修改了MyClass类,使其实现ICloneable接口,并实现了ICloneable的一个方法Clone。
protected class MyClass : ICloneable
{
public int i;
public int j;
public string message;
public object Clone()
{
MyClass mc = new MyClass();
mc.i = i;
mc.j = j;
if (message != null)
mc.message = String.Copy(message);
return mc;
}
}
private void Test()
{
MyClass mc1 = new MyClass();
mc1.i = 5;
mc1.j = 10;
mc1.message = "Hello, World!";
MyClass mc2 = (MyClass)mc1.Clone();
}