熱點推薦:
您现在的位置: 電腦知識網 >> 編程 >> .NET編程 >> 正文

C#淺拷貝與深拷貝區別

2013-11-13 10:17:01  來源: .NET編程 

  也許會有人這樣解釋C# 中淺拷貝與深拷貝區別

  淺拷貝是對引用類型拷貝地址對值類型直接進行拷貝

  不能說它完全錯誤但至少還不夠嚴謹比如string 類型咋說?

  其實我們可以通過實踐來尋找答案

  首先定義以下類型

  int string enum struct class int[ ] string[ ]

  代碼如下

  //枚舉

  public enum myEnum

  { _ = _ = }

  //結構體

  public struct myStruct

  {

  public int _int;

  public myStruct(int i)

  { _int = i; }

  }

  //類

  class myClass

  {

  public string _string;

  public myClass(string s)

  { _string = s; }

  }

  //ICloneable創建作為當前實例副本的新對象

  class DemoClass : ICloneable

  {

  public int _int = ;

  public string _string = ;

  public myEnum _enum = myEnum_;

  public myStruct _struct = new myStruct();

  public myClass _class = new myClass();

  //數組

  public int[] arrInt = new int[] { };

  public string[] arrString = new string[] { };

  //返回此實例副本的新對象

  public object Clone()

  {

  //MemberwiseClone返回當前對象的淺表副本(它是Object對象的基方法)

  return thisMemberwiseClone();

  }

  }

  注意

  ICloneable 接口支持克隆即用與現有實例相同的值創建類的新實例

  MemberwiseClone 方法創建當前 SystemObject 的淺表副本

  接下來構建實例A 並對實例A 克隆產生一個實例B

  然後改變實例B 的值並觀察實例A 的值會不會被改變

  代碼如下

  class 淺拷貝與深拷貝

  {

  static void Main(string[] args)

  {

  DemoClass A = new DemoClass();

  //創建實例A的副本 > 新對象實例B

  DemoClass B = (DemoClass)AClone();

  B_int = ;

  ConsoleWriteLine( int \t\t  A:{}  B:{} A_int B_int);

  B_string = ;

  ConsoleWriteLine( string \t  A:{}  B:{} A_string B_string);

  B_enum = myEnum_;

  ConsoleWriteLine( enum \t\t  A:{}  B:{} (int)A_enum (int)B_enum);

  B_struct_int = ;

  ConsoleWriteLine( struct \t  A:{}  B:{}

  A_struct_int B_struct_int);

  B_class_string = ;

  ConsoleWriteLine( class \t\t  A:{}  B:{}

  A_class_string B_class_string);

  BarrInt[] = ;

  ConsoleWriteLine( intArray \t  A:{}  B:{}

  AarrInt[] BarrInt[]);

  BarrString[] = ;

  ConsoleWriteLine( stringArray \t  A:{}  B:{}

  AarrString[] BarrString[]);

  ConsoleReadKey();

  }

  }

  結果如下

  2010-09-08_221736

  從最後的輸出結果我們得知

  對於內部的Class 對象和數組則Copy 一份地址[ 改變B 時A也被改變了 ]

  而對於其它內置的int / string / enum / struct / object 類型則Copy 一份值

  有一位網友說string 類型雖然是引用類型但是很多情況下Net 把string 做值類型來處理我覺得string 應該也是按照值類型處理的

  這說明他對string 類型還不夠了解

  可以肯定的是string 一定是引用類型那它為什麼是深拷貝呢?

  如果你看一下string 類型的源代碼就知道了

  //表示空字符串此字段為只讀

  public static readonly string Empty;

  答案就在於 string 是 readonly 的當改變 string 類型的數據值時將重新分配了內存地址

  下面引用一段網友的代碼Vseen[ Aloner ] 的個人陋見

  public class Student

  {

  // 這裡用字段其實應當是屬性

  public string Name;

  public int Age;

  //自定義類 Classroom

  public Classroom Class;

  }

  淺拷貝Student A 淺拷貝出 Student BName和Age擁有新的內存地址但引用了同一個 Classroom

  深拷貝Student A 淺拷貝出 Student BName和Age擁有新的內存地址並且AClassroom 的內存地址不等於 BClassroom

  其實俗點講有點像

  public object Clone()

  {

  Student B = new Student();

  BName = thisName;

  BAge = thisAge;

  //淺拷貝

  BClass = thisClass;

  //深拷貝

  BClass = new Classromm();

  BClassName = thisClassName;

  BClassTeacher = thisClassTeacher;

  //根據情況對Teacher 進行判定要進行的是深拷貝還是淺拷貝

  }

  淺拷貝給對象拷貝一份新的對象

  淺拷貝的定義 —— 只對值類型(或string)類型分配新的內存地址

  深拷貝給對象拷貝一份全新的對象

  深拷貝的定義 —— 對值類型分配新的內存地址引用類型以及引用類型的內部字段分配的新的地址

  我是這麼定義的淺拷貝換湯不換藥

  注意

  NET 程序中應該避免使用 ICloneable 接口

  因為通過該接口無法判斷究竟是淺拷貝還是深拷貝這會造成誤解或誤用

  深拷貝應該復制該對象本身及通過該對象所能到達的完整的對象圖淺拷貝只復制對象本身(就是該對象所表示的在堆中的一塊連續地址中的內容)

  個人愚見

  Clone 深層拷貝拷貝到了指針指向的內存塊的值

  淺拷貝僅僅拷貝了指針的內容(只是給一個對象多起了個名字所以當改變拷貝的某個屬性的時候原對象的對應屬性亦會改變)


From:http://tw.wingwit.com/Article/program/net/201311/13157.html
    推薦文章
    Copyright © 2005-2013 電腦知識網 Computer Knowledge   All rights reserved.