不可不知的C#基礎–從 struct 和 class的異同 說開去

來源:互聯網
上載者:User

 

我知道很多人都討論過這個問題, 多我一個不多, 少我一個不少.

最近有人又問到這個問題, 所以想再說說. 萬丈高樓平地起, 地基很重要. 懂了的人不要嫌羅嗦, 歡迎補充或者糾正.

從起源/定義說起

Struct 從C 的時代就已經有了(向丹尼斯.裡奇致敬), 它是Structure 的縮寫 -- 就是結構的意思. 它是一種最初級的資料結構, 它包含一到多個相同類型或不同類型的值或者變數. 它就像是一個儲存資料的"包".

 

Class(類) 是有了物件導向概念之後才有的, 它"是建立對象的藍圖,描述了所建立的對象共同的屬性和方法".

 

從它們被創立的用途可以看出Class 比Struct 負擔了更大的使命.

類從出生的那天就被賦予了一個偉大的使命: 類比真實世界的行為, 擁有繼承和多態兩種利器.

Struct 到了C#這個領域中有了一個進化, 它甚至可以實現介面(當然,這個也是C時代沒有的東西), 在本文中會有一個簡單的介紹.

 

實值型別 VS 參考型別在.net 世界中, System.Object "支援 .NET Framework 類階層中的所有類,並為衍生類別提供低層級服務。 這是 .NET Framework 中所有類的最終基類;它是類型階層的根。" 從Object再衍生出所有類、結構、枚舉和委託。看看下面這個圖對net中兩大類型的描述, -- 當然還有一種"指標類型",在這裡我們不予討論.

 

 

Struct 是屬於實值型別這個陣容, 而所有class 都是參考型別.

這意味著什麼?

 

當我們使用等號"賦值"時, 對於Struct而言就是將同樣的值複製給另一個變數; 而對於Class而言就只是將它們的名字指向同一個對象.

 

看下面的執行個體:

class FooClass{    public int FooValue;}struct FooStruct{    public int FooValue;}class Program{    static void Main(string[] args)    {        FooClass classObj = new FooClass();        classObj.FooValue = 0;        FooClass classObj2 = classObj;        classObj2.FooValue = 1;        FooStruct structObj = new FooStruct();        structObj.FooValue = 0;        FooStruct structObj2 = structObj;                structObj2.FooValue = 1;    }}
再最後設個斷點, 運行後取值:  structObj2 在初始時, 會建立一個全新的副本, 然後擷取structObj 的所有數值;classObj2 在初始時, 只是指向了classObj. 這就是實值型別和參考型別的一個區別. 當修改classObj 或者 classObj2 時, 修改的是同一部分記憶體.Struct實現介面

前面提到了Struct可以實現介面, 下面我們引用一個執行個體:

interface IPromotion{    void promote();}struct Employee : IPromotion{    public string Name;    public int JobGrade;    public void promote()    {        JobGrade++;    }    public Employee(string name, int jobGrade)    {        this.Name = name;        this.JobGrade = jobGrade;    }    public override string ToString()    {        return string.Format("{0} ({1})", Name, JobGrade);    }}class Program{    static void Main(string[] args)    {        Employee employee = new Employee("Cool Guy", 65);        IPromotion p = employee;        Console.WriteLine(employee);        p.promote();        Console.WriteLine(employee);    }}
一旦增加了這個功能, 我們就可以在應用Struct之前, 給予其一些介面的定義. 使一類的struct 在形式上保持一致. 不同的用途

使用中在struct 和 class 兩者間該選誰?

我們在編程中要實現某種資料結構時, 絕大部分情況下我們會選擇class -- 因為它的強大和特定的使命. 但是當我們要傳遞或儲存一些小資料結構時,可以考慮struct.

Net framework 下有很多已經定義好了的struct例如:

System.Drawing.Rectangle
System.Drawing.Color
System.Drawing.Point

使用時要記住struct的特性.

 

 

那麼我再補充幾點吧:
初始化方面:
實值型別分配在堆棧上,變數本身包含了執行個體所有欄位。
參考型別分配在託管堆上,被分配在託管堆上的對象都有一些與之關聯的額外成員要被初始化。分配完後返回對象位於託管堆的地址。

記憶體釋放方面:
實值型別沒有分配在託管堆,所以不受GC控制。一旦實值型別不被引用,為它分配的儲存空間就會立即釋放。實值型別也有Finalize方法,但被回收時,CLR不會調用該方法。
參考型別受GC控制。

繼承方面:
不能把實值型別當作基類,所以實值型別裡不要有虛方法,也沒有抽象方法,所有的方法都隱含有sealed修飾符。

用途方面:
實值型別不要頻繁用於方法的參數傳遞。因為參數以傳值的方式傳遞,導致實值型別的欄位頻繁被拷貝。
實值型別不要作為方法傳回值頻繁返回。原因同上。
實值型別不要頻繁用於ArrayList,Hashtable類。因為一不小心會頻繁裝箱。

實值型別的裝箱與拆箱可以講很多。
就舉一個例子,什麼時候裝箱比較好。
int a=5;
Console.WriteLine("{0},{1},{2}",a,a,a);//反例
Object o=a;//裝箱
Console.WriteLine("{0},{1},{2}",o,o,o);

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.