1. 程式人生 > >.NET技術:.NET中class和struct的區別

.NET技術:.NET中class和struct的區別

1、引言

  提起class和struct,我們首先的感覺是語法幾乎相同,待遇卻天壤之別。歷史將接力棒由面向過程程式設計傳到面向物件程式設計,class和struct也揹負著各自的命運前行。在我認為,struct英雄遲暮,class天下獨行,最本質的區別是class是引用型別,而struct是值型別,它們在記憶體中的分配情況有所區別。由此產生的一系列差異性,本文將做以全面討論。

  2、基本概念

  2.1、什麼是class?

  class(類)是面向物件程式設計的基本概念,是一種自定義資料結構型別,通常包含欄位、屬性、方法、屬性、建構函式、索引器、操作符等。因為是 基本的概念,所以不必在此詳細描述,讀者可以查詢相關概念瞭解。我們重點強調的是.NET中,所有的類都最終繼承自System.Object類,因此是 一種引用型別,也就是說,new一個類的例項時,物件儲存了該例項實際資料的引用地址,而物件的值儲存在

託管堆(managed heap)中。

  2.2、什麼是struct?

  struct(結構)是一種值型別,用於將一組相關的資訊變數組織為一個單一的變數實體 。所有的結構都繼承自System.ValueType類,因此是一種值型別,也就是說,struct例項分配在執行緒的堆疊(stack)上,它本身儲存了值,而不包含指向該值的指標。所以在使用struct時,我們可以將其當作int、char這樣的基本型別類對待。


 3、相同點,不同點

  相同點:語法類似。

  不同點:

  ◆class是引用型別,繼承自System.Object類;struct是值型別,繼承自System.ValueType類,因此不具多型性。但是注意,System.ValueType是個引用型別。

  ◆從職能觀點來看,class表現為行為;而struct常用於儲存資料。

  ◆class支援繼承,可以繼承自類和介面;而struct沒有繼承性,struct不能從class繼承,也不能作為class的基類,但struct支援介面繼承。

◆class可以宣告無參建構函式,可以宣告解構函式;而struct只能宣告帶引數建構函式,且不能宣告解構函式。因此,struct沒有自定義的預設無參建構函式,預設無參構造器只是簡單地把所有值初始化為它們的0等價值。

  ◆例項化時,class要使用new關鍵字;而struct可以不使用new關鍵字,struct在宣告時就進行了初始化過程,所有的成員變數均預設為0或null。

  ◆class可以實抽象類(abstract),可以宣告抽象函式;而struct為抽象,也不能宣告抽象函式。

  ◆class可以宣告protected成員、virtual成員、sealed成員和override成員;而struct不可以,但是值得 注意的是,struct可以過載System.Object的3個虛方法,Equals()、ToString()和GetHashTable()。

  ◆class的物件複製分為淺拷貝和深拷貝,必須經過特別的方法來完成複製;而struct建立的物件複製簡單,可以直接以等號連線即可。

  ◆class例項由垃圾回收機制來保證記憶體的回收處理;而struct變數使用完後立即自動解除記憶體分配。

  ◆作為引數傳遞時,class變數是以按址方式傳遞;而struct變數是以按值方式傳遞的。

  我們可以簡單的理解,class是一個可以動的機器,有行為,有多型,有繼承;而struct就是個零件箱,組合了不同結構的零件。其實, class和struct最本質的區別就在於class是引用型別,記憶體分配於託管堆;而struct是值型別,記憶體分配於執行緒的堆疊上。由此差異,導致 了上述所有的不同點,所以只有深刻的理解記憶體分配的相關內容,才能更好的駕馭。本系列將再以後的內容中,將引用型別和值型別做以深入的比較和探討,敬請關 注。當然正如本文標題描述的一樣,使用class基本可以替代struct的任何場合,class後來居上。雖然在某些方面struct有效能方面的優 勢,但是在面向物件程式設計裡,基本是class橫行的天下。

  那麼,有人不免會提出,既然class幾乎可以完全替代struct來實現所有的功能,那麼struct還有存在的必要嗎?答案是,至少在以下情況下,鑑於效能上的考慮,我們應該考慮使用struct來代替class:

  ◆實現一個主要用於儲存資料的結構時,可以考慮struct。

  ◆struct變數佔有堆疊的空間,因此只適用於資料量相對小的場合。

  ◆結構陣列具有更高的效率。

  ◆提供某些和非託管程式碼通訊的相容性。

  所有這些是struct有一席之地的理由,當然也許還有其他的更多說法,只是我不知道罷了。

  4、經典示例

  4.1、小菜一碟

  下面以示例為說明,來闡述本文的基本規則,詳細見註釋內容。

  (1)定義介面

      interface IPerson

  {

  void GetSex();

  }

 (2)定義類

      public class Person

  {

  public Person()

  {

  }

  public Person(string name, int age)

  {

  _name = name;

  _age = age;}

  private string _name;

  public string Name

  {

  get { return _name; }

  set { _name = value; }

  }

  private int _age;

  public int Age

  {

  get { return _age; }

  set { _age = value; }

  }

  }

(3)定義結構

  //可以繼承自介面,不可繼承類或結構

      struct Family: IPerson

  {

  public string name;

  public int age;

  public bool sex;

  public string country;

  public Person person;

  //不可以包含顯式的無參建構函式和解構函式

  public Family(string name, int age, bool sex, string country, Person person)

  {

  this.name = name;

  this.age = age;

  this.sex = sex;

  this.country = country;

  this.person = person;

  }

  //不可以實現protected、virtual、sealed和override成員

  public void GetSex()

  {

  if (sex)

  Console.WriteLine(person.Name + " is a boy.");

  else

  Console.WriteLine(person.Name + " is a girl.");

  }

  public void ShowPerson()

  {

  Console.WriteLine("This is {0} from {1}", new Person(name, 22).Name, country);

  }

  //可以過載ToString虛方法

  public override string ToString()

  {

  return String.Format("{0} is {1}, {2} from {3}", person.Name, age, sex ? "Boy" : "Girl", country);

  }

  }

(4)測試結構和類


 猜猜執行結果如何,可以順便檢查檢查對這個概念的認識。

  4.2、.NET研究

  在.NET框架中,System.Drawing名稱空間中的有些元素,如System.Drawing.Point就是實現為struct, 而不是class。其原因也正在於以上介紹的各方面的權衡,大家可以就此研究研究,可以體會更多。另外,還有以struct實現的 System.Guid。

  5、結論

  對基本概念的把握,是我們進行技術深入探索的必經之路,本系列的主旨也是能夠從基本框架中,提供給大家一個通向高階技術的必修課程。本文關於 class和struct的討論就是如此,在.NET框架中,關於class和struct的討論將涉及到對引用型別和值型別的認識,並且進一步將觸角伸 向變數記憶體分配這一高階主題,所以我們有必要來了解其執行機制,把握區別和應用場合,以便在平常的系統設計中把握好對這一概念層次的把握。