第一次写技术博文,手生的很,水平也有限,有什么不对的地方大家多多指教。
大家都知道class是引用类型,如果将一个引用变量分配给另一个引用变量,那么这个赋值操作进行的是一个浅拷贝,这两个引用变量将指向内存中的同一个对象。 我们有这样一个类的赋值操作就是执行这样的操作。
{
private int _X;
private int _Y;
public TestClass(int x,int y)
{
this._X = x;
this._Y = y;
}
public int X
{
set { this._X = value; }
}
}
static void Main(string[] args)
{
TestClass class1 = new TestClass(1, 1);
TestClass class2 = class1;
class2.X = 2;
}
这样的情况下我们修改class2的X值那么class1中X的值也会跟着改变。
有些情况下我们需要现有类实例的一个副本该怎么办呢?这时候就需要我们实现ICloneable接口了。
ICloneable接口的定义如下:
public interface ICloneable
{
// 摘要:
// Creates a new object that is a copy of the current instance.
//
// 返回结果:
// A new object that is a copy of this instance.
object Clone();
}
ComVisible特性是设置是否允许COM客户端访问,我们这里不详细说。
如果我们希望自己的自定义类提供深拷贝能力的话具体分两种情况,一种情况是我们的自定义类中不包含引用类型的变量;另一种情况当然就是包含引用类型的变量了。下面我们分别说明这两种情况。 现在我们的TestClass类只有两个成员变量_X,_Y都是值类型的变量,值类型变量不包含指向实例的指针,它本身即包含了实例的所有内容,所以我们只需要实现ICloneable接口的Clone()方法在方法中依次复制每个值类型字段即可,Clone方法为
{
//因为我们的字段都是在构造器中赋值的,所以以相同的值构建一个新的实例即可
return new TestClass(_X, _Y);
}
.net中所有的类型都最终继承自System.Object类型,所以我们可以继续改进上面的Clone方法,使用System.Object类型提供的受保护方法
MemberwiseClone,该方法创建新的类型实例,并将字段设置为和this对象的字段相同,现在我们的字段都是值类型的所以该方法即可获得实例的单独副本。
Clone方法修改为:
{
//逐个复制TestClass的每个字段
return base.MemberwiseClone();
}
现在TestClass修改为:
{
private int _X;
private int _Y;
public TestClass(int x,int y)
{
this._X = x;
this._Y = y;
}
public int X
{
set { this._X = value; }
}
public object Clone()
{
//逐个复制TestClass的每个字段
return base.MemberwiseClone();
}
}
这样我们就可以获得TestClass的单独副本了,如下所示:
{
TestClass class1 = new TestClass(1, 1);
TestClass class2 = (TestClass)class1.Clone();
//改变class2不影响class1
class2.X = 2;
}
包含引用变量字段的类型,实现深拷贝的方式跟上面的方法类似,只是需要注意引用类型在栈中保存的是指向托管堆的指针所有直接赋值和MemberwiseClone方法都是把指针地址复制,实际上还是指向同一个实例。我们需要在Clone方法中用同样的值构建全新的类型实例并返回。