第一次寫技術博文,手生的很,水平也有限,有什麼不對的地方大家多多指教。
大家都知道class是參考型別,如果將一個引用變數分配給另一個引用變數,那麼這個賦值操作進行的是一個淺拷貝,這兩個引用變數將指向記憶體中的同一個對象。 我們有這樣一個類的賦值操作就是執行這樣的操作。
代碼
public class 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; }
}
}
static void Main(string[] args)
{
TestClass class1 = new TestClass(1, 1);
TestClass class2 = class1;
class2.X = 2;
}
這樣的情況下我們修改class2的X值那麼class1中X的值也會跟著改變。
有些情況下我們需要現有類執行個體的一個副本該怎麼辦呢?這時候就需要我們實現ICloneable介面了。
ICloneable介面的定義如下:
代碼
[ComVisible(true)]
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方法為
public object Clone()
{
//因為我們的欄位都是在構造器中賦值的,所以以相同的值構建一個新的執行個體即可
return new TestClass(_X, _Y);
}
.net中所有的類型都最終繼承自System.Object類型,所以我們可以繼續改進上面的Clone方法,使用System.Object類型提供的受保護方法
MemberwiseClone,該方法建立新的類型執行個體,並將欄位設定為和this對象的欄位相同,現在我們的欄位都是實值型別的所以該方法即可獲得執行個體的單獨副本。
Clone方法修改為:
public object Clone()
{
//逐個複製TestClass的每個欄位
return base.MemberwiseClone();
}
現在TestClass修改為:
代碼public class TestClass:ICloneable
{
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的單獨副本了,如下所示:
代碼static void Main(string[] args)
{
TestClass class1 = new TestClass(1, 1);
TestClass class2 = (TestClass)class1.Clone();
//改變class2不影響class1
class2.X = 2;
}
包含引用變數欄位的類型,實現深拷貝的方式跟上面的方法類似,只是需要注意參考型別在棧中儲存的是指向託管堆的指標所有直接賦值和MemberwiseClone方法都是把指標地址複製,實際上還是指向同一個執行個體。我們需要在Clone方法中用同樣的值構建全新的類型執行個體並返回。