通過下面的GetCopy()方法,介紹了如何使用受保護(hù)的方法System.Object.MemberwiseClone()進(jìn)行淺度復(fù)制。
public class Cloner
{
public int Val;
public Cloner{int newVal) => Val = newVal;
public object GetCopy() => MemberwiseClone();
}
假定有一些引用類型的字段,而不是值類型的字段(例如,對(duì)象):
public class Content
{
public int Val;
}
public class Cloner
{
public Content MyContent = new Content();
public Cloner(int newVal) => MyContent.Val s newVal;
public object GetCopy() => MemberwiseClone();
}
此時(shí),通過GetCopyO得到的淺度復(fù)制包括一個(gè)字段,它引用的對(duì)象與源對(duì)象相同。以下代碼使用這個(gè)Cloner類來說明淺度復(fù)制引用類型的結(jié)果:
Cloner mySource = new Cloner(5);
Cloner myTarget = (Cloner)mySource.GetCopy();
WriteLine($"myTarget.MyContent.Val = {myTarget-MyContent.Val}");
mySource.MyContent.Val =2;
WriteLine($"myTarget.MyContent.Val = (myTarget .MyContent.Val}");
第4行把一個(gè)值賦給mySource.MyContent.Val,它是源對(duì)象中公共字段MyContent的公共字段Val。這也改變了 myTarget.MyContent.Val 的值。這是因?yàn)?mySource.MyContent 引用了與 myTargetMyContent 相同的對(duì)象實(shí)例。上述代碼的輸出結(jié)果如下:
myTarget.MyContent.Val = 5
myTarget.MyContent.Val = 2
為解決這個(gè)問題,需要執(zhí)行深度復(fù)制。修改上面的GetCopyO方法就可以進(jìn)行深度復(fù)制,但最好使用.NET Framework的標(biāo)準(zhǔn)方式:實(shí)現(xiàn)ICloneable接口,該接口有一個(gè)Clone()方法;這個(gè)方法不帶參數(shù),返回一個(gè)object類型的結(jié)果,其簽名和上面使用的GetCopy()方法相同。
為修改上面的類,可使用下面的深度復(fù)制代碼:
public class Content
{
public int Val;
}
public class Cloner : ICloneable
{
public Content MyContent = new Content 0;
public Cloner(int newVal) => MyContent.Val = newVal;
public object Clone()
{
Cloner clonedCloner = new Cloner(MyContent.Val);
return clonedCloner;
}
}
其中使用包含在源Cloner對(duì)象中的Content對(duì)象(MyContent)的Val字段,創(chuàng)建了一個(gè)新對(duì)象Cloner。這個(gè)字段是一個(gè)值類型,所以不需要深度復(fù)制。
使用與上面類似的代碼來測試淺度復(fù)制,但用CloneO替代GetCopy(),得到如下結(jié)果:
myTarget.MyContent.Val = 5
myTarget,MyContent.Val = 5
這次包含的對(duì)象是獨(dú)立的。注意有時(shí)在比較復(fù)雜的對(duì)象系統(tǒng)中,調(diào)用Clone()是一個(gè)遞歸過程。例如,如果Cloner類的MyContent字段也需要深度復(fù)制,就要使用下面的代碼:
public class Cloner : ICloneable
{
public Content MyContent = new Content();
...
public object Clone()
{
Cloner clonedCloner = new Cloner();
clonedCloner.MyContent = MyContent.Clone();
return clonedCloner;
}
}
這里調(diào)用了默認(rèn)的構(gòu)造函數(shù),以便簡化創(chuàng)建新對(duì)象Cloner的語法。為使這段代碼能正常工作,還需要在 Content 類上實(shí)現(xiàn) ICloneable 接口。
點(diǎn)擊加載更多評(píng)論>>