今天我們談談C#中的對象拷貝問題;
所謂的對象拷貝,其實就是為對象創(chuàng)建副本,C#中將拷貝分為兩種,分別為淺拷貝和深拷貝;
所謂淺拷貝就是將對象中的所有字段復制到新的副本對象中;淺拷貝對于值類型與引用類型的方式有區(qū)別,值類型字段的值被復制到副本中后,在副本中的修改不會影響源對象對應的值;然而對于引用類型的字段被復制到副本中的卻是引用類型的引用,而不是引用的對象,在副本中對引用類型的字段值被修改后,源對象的值也將被修改。
深拷貝也同樣是將對象中的所有字段復制到副本對象中,但是,無論對象的值類型字段或者引用類型字段,都會被重新創(chuàng)建并復制,對于副本的修改,不會影響到源對象的本身;
當然,無論是哪種拷貝,微軟都建議使用類型繼承ICloneable接口的方式明確告訴調(diào)用者,該對象是否可用被拷貝。當然了,ICloneable接口只提供了一個聲明為Clone的方法,我們可以根據(jù)需求在Clone的方法內(nèi)實現(xiàn)淺拷貝或者是深拷貝
淺拷貝和深拷貝的區(qū)別
淺拷貝是指將對象中的數(shù)值類型的字段拷貝到新的對象中,而對象中的引用型字段則指復制它的一個引用到目標對象。如果改變目標對象 中引用型字段的值他將反映在原是對象中,也就是說原始對象中對應的字段也會發(fā)生變化。深拷貝與淺拷貝不同的是對于引用的處理,深拷貝將會在新對象中創(chuàng)建一 個新的和原是對象中對應字段相同(內(nèi)容相同)的字段,也就是說這個引用和原是對象的引用是不同的,我們在改變新對象中的這個字段的時候是不會影響到原始對 象中對應字段的內(nèi)容。所以對于原型模式也有不同的兩種處理方法:對象的淺拷貝和深拷貝。
深淺拷貝的幾種實現(xiàn)方式
上面已經(jīng)明白了深淺拷貝的定義,至于他們之間的區(qū)別也在定義中也有所體現(xiàn)。介紹完了它們的定義和區(qū)別之后,自然也就有了如何去實現(xiàn)它們呢?
對于,淺拷貝的實現(xiàn)方式很簡單,.NET自身也提供了實現(xiàn)。我們知道,所有對象的父對象都是System.Object對象,這個父對象中有一個MemberwiseClone方法,該方法就可以用來實現(xiàn)淺拷貝,下面具體看看淺拷貝的實現(xiàn)方式,具體演示代碼如下所示:
// 繼承ICloneable接口,重新其Clone方法
class ShallowCopyDemoClass : ICloneable
{
public int intValue = 1;
public string strValue = “1”;
public PersonEnum pEnum = PersonEnum.EnumA;
public PersonStruct pStruct = new PersonStruct() { StructValue = 1};
public Person pClass = new Person(“1”);
public int[] pIntArray = new int[] { 1 };
public string[] pStringArray = new string[] { “1” };
#region ICloneable成員
public object Clone()
{
return this.MemberwiseClone();
}
#endregion
}
class Person
{
public string Name;
public Person(string name)
{
Name = name;
}
}
public enum PersonEnum
{
EnumA = 0,
EnumB = 1
}
public struct PersonStruct
{
public int StructValue;
}
上面類中重寫了IConeable接口的Clone方法,其實現(xiàn)直接調(diào)用了Object的MemberwiseClone方法來完成淺拷貝,如果想實現(xiàn)深拷貝,也可以在Clone方法中實現(xiàn)深拷貝的邏輯。接下來就是對上面定義的類進行淺拷貝測試了,看看是否是實現(xiàn)的淺拷貝,具體演示代碼如下所示:
class Program
{
static void Main(string[] args)
{
ShallowCopyDemo();
// List淺拷貝的演示
ListShallowCopyDemo();
}
public static void ListShallowCopyDemo()
{
List《PersonA》 personList = new List《PersonA》()
{
new PersonA() { Name=“PersonA”, Age= 10, ClassA= new A() { TestProperty = “AProperty”} },
new PersonA() { Name=“PersonA2”, Age= 20, ClassA= new A() { TestProperty = “AProperty2”} }
};
// 下面2種方式實現(xiàn)的都是淺拷貝
List《PersonA》 personsCopy = new List《PersonA》(personList);
PersonA[] personCopy2 = new PersonA[2];
personList.CopyTo(personCopy2);
// 由于實現(xiàn)的是淺拷貝,所以改變一個對象的值,其他2個對象的值都會發(fā)生改變,因為它們都是使用的同一份實體,即它們指向內(nèi)存中同一個地址
personsCopy.First().ClassA.TestProperty = “AProperty3”;
WriteLog(string.Format(“personCopy2.First().ClassA.TestProperty is {0}”, personCopy2.First().ClassA.TestProperty));
WriteLog(string.Format(“personList.First().ClassA.TestProperty is {0}”, personList.First().ClassA.TestProperty));
WriteLog(string.Format(“personsCopy.First().ClassA.TestProperty is {0}”, personsCopy.First().ClassA.TestProperty));
Console.Read();
}
public static void ShallowCopyDemo()
{
ShallowCopyDemoClass DemoA = new ShallowCopyDemoClass();
ShallowCopyDemoClass DemoB = DemoA.Clone() as ShallowCopyDemoClass ;
DemoB.intValue = 2;
WriteLog(string.Format(“ int-》[A:{0}] [B:{1}]”, DemoA.intValue, DemoB.intValue));
DemoB.strValue = “2”;
WriteLog(string.Format(“ string-》[A:{0}] [B:{1}]”, DemoA.strValue, DemoB.strValue));
DemoB.pEnum = PersonEnum.EnumB;
WriteLog(string.Format(“ Enum-》[A: {0}] [B:{1}]”, DemoA.pEnum, DemoB.pEnum));
DemoB.pStruct.StructValue = 2;
WriteLog(string.Format(“ struct-》[A: {0}] [B: {1}]”, DemoA.pStruct.StructValue, DemoB.pStruct.StructValue));
DemoB.pIntArray[0] = 2;
WriteLog(string.Format(“ intArray-》[A:{0}] [B:{1}]”, DemoA.pIntArray[0], DemoB.pIntArray[0]));
DemoB.pStringArray[0] = “2”;
WriteLog(string.Format(“stringArray-》[A:{0}] [B:{1}]”, DemoA.pStringArray[0], DemoB.pStringArray[0]));
DemoB.pClass.Name = “2”;
WriteLog(string.Format(“ Class-》[A:{0}] [B:{1}]”, DemoA.pClass.Name, DemoB.pClass.Name));
Console.WriteLine();
}
private static void WriteLog(string msg) { Console.WriteLine(msg); } } }
上面代碼的運行結(jié)果如下圖所示:
評論
查看更多