国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

編寫高質量代碼改善C#程序的157個建議——建議14:正確實現淺拷貝和深拷貝

2019-11-14 14:10:24
字體:
來源:轉載
供稿:網友

建議14: 正確實現淺拷貝和深拷貝

為對象創建副本的技術稱為拷貝(也叫克隆)。我們將拷貝分為淺拷貝和深拷貝。

  • 淺拷貝 將對象中的所有字段復制到新的對象(副本)中。其中,值類型字段的值被復制到副本中后,在副本中的修改不會影響到源對象對應的值。而引用類型的字段被復制到副本中的是引用類型的引用,而不是引用的對象,在副本中對引用類型的字段值做修改會影響到源對象本身。
  • 深拷貝 同樣,將對象中的所有字段復制到新的對象中。不過,無論是對象的值類型字段,還是引用類型字段,都會被重新創建并賦值,對于副本的修改,不會影響到源對象本身。

無論是淺拷貝還是深拷貝,微軟都建議用類型繼承ICloneable接口的方式明確告訴調用者:該類型可以被拷貝。當然,ICloneable接口 只提供了一個聲明為Clone的方法,我們可以根據需求在Clone方法內實現淺拷貝或深拷貝。一個簡單的淺拷貝的實現代碼如下所示:

    class Employee : ICloneable      {          public string IDCode { get; set; }          public int Age { get; set; }          public Department Department { get; set; }               #region ICloneable 成員               public object Clone()          {              return this.MemberwiseClone();          }               #endregion      }           class Department      {          public string Name { get; set; }          public override string ToString()          {              return this.Name;          }      } 

 

調用方代碼如下所示:

    Employee mike = new Employee() { IDCode = "NB123", Age = 30, Department = new Department() { Name = "Dep1" } };      Employee rose = mike.Clone() as Employee;      Console.WriteLine(rose.IDCode);      Console.WriteLine(rose.Age);      Console.WriteLine(rose.Department);      Console.WriteLine("開始改變mike的值:");      mike.IDCode = "NB456";      mike.Age = 60;      mike.Department.Name = "Dep2";      Console.WriteLine(rose.IDCode);      Console.WriteLine(rose.Age);      Console.WriteLine(rose.Department); 

 

輸出為:

NB123  30  Dep1 開始改變mike的值:NB123  30  Dep2 

 

注意到Employee的IDCode屬性是string類型。理論上string類型是引用類型,但是由于該引用類型的特殊性(無論是實現還是語義),Object.MemberwiseClone方法仍舊為其創建了副本。也就是說,在淺拷貝過程,我們應該將字符串看成是值類型。 Employee的Department屬性是一個引用類型,所以,如果改變了源對象mike中的值,副本rose中的值也會隨之一起變動。 Employee的深拷貝有多種實現方法,最簡單的方法是手動對字段逐個進行賦值。但這種方法容易出錯,也就是說,如果類型的字段發生變化或有增減,那么 該拷貝方法也要發生相應的變化,所以,建議使用序列化的形式來進行深拷貝。Employee深拷貝的一個簡單實現代碼如下所示:

    class Employee : ICloneable      {          public string IDCode { get; set; }          public int Age { get; set; }          public Department Department { get; set; }               #region ICloneable 成員               public object Clone()          {              using (Stream objectStream = new MemoryStream())              {                  IFormatter formatter = new BinaryFormatter();                  formatter.Serialize(objectStream, this);                  objectStream.Seek(0, SeekOrigin.Begin);                  return formatter.Deserialize(objectStream) as Employee;              }          }          #endregion      } 

 

使用淺拷貝中的調用者代碼,輸出為:

NB123  30  Dep1 開始改變mike的值:NB123  30  Dep1 

 

可以發現,再次更改mike的值已經不會影響副本rose的值了。 由于接口ICloneable只有一個模棱兩可的Clone方法,所以,如果要在一個類中同時實現深拷貝和淺拷貝,只能由我們自己實現兩個額外的方法,聲明為DeepClone和Shallow。Employee的最終版本看起來應該像如下的形式:

    [Serializable]      class Employee : ICloneable      {          public string IDCode { get; set; }          public int Age { get; set; }          public Department Department { get; set; }               #region ICloneable 成員               public object Clone()          {              return this.MemberwiseClone();          }               #endregion               public Employee DeepClone()          {              using (Stream objectStream = new MemoryStream())              {                  IFormatter formatter = new BinaryFormatter();                  formatter.Serialize(objectStream, this);                  objectStream.Seek(0, SeekOrigin.Begin);                  return formatter.Deserialize(objectStream) as Employee;              }          }               public Employee ShallowClone()          {              return Clone() as Employee;          }      }

 

轉自:《編寫高質量代碼改善C#程序的157個建議》陸敏技


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 当阳市| 普定县| 吉林省| 南陵县| 会东县| 青岛市| 友谊县| 乐陵市| 东台市| 中阳县| 青神县| 丰台区| 土默特右旗| 荔波县| 嘉义市| 台安县| 雅江县| 西乡县| 南召县| 张家港市| 金门县| 宁明县| 武邑县| 博客| 乡宁县| 凤台县| 五指山市| 吴堡县| 上思县| 开封市| 新乐市| 绥化市| 湟源县| 安多县| 西畴县| 双鸭山市| 西乌珠穆沁旗| 阿合奇县| 江西省| 桃园市| 庄河市|