何時應該在C#中使用struct而不是class? 個人概念模型是當項只是值類型的集合時使用結構。 一種邏輯上將它們組合在一塊兒造成一個有凝聚力的總體的方法。 web
我在這裏遇到了這些規則: 數組
這些規則有效嗎? 結構在語義上意味着什麼? 緩存
C#或其餘.net語言中的結構類型一般用於保存應該像固定大小的值組同樣的事物。 結構類型的一個有用方面是結構類型實例的字段能夠經過修改其所在的存儲位置來修改,而不是以其餘方式。 能夠以這樣的方式對結構進行編碼:改變任何字段的惟一方法是構造一個全新的實例,而後使用結構賦值經過用新實例中的值覆蓋它們來改變目標的全部字段,可是除非struct沒有提供建立其字段具備非默認值的實例的方法,不然若是struct自己存儲在可變位置,則其全部字段都是可變的。 數據結構
請注意,若是結構包含私有類類型字段,而且將其本身的成員重定向到包裝類對象的成員,則能夠設計一種結構類型,使其基本上表現得像類類型。 例如, PersonCollection
可能提供屬性SortedByName
和SortedById
,這兩個屬性都包含對PersonCollection
(在其構造函數中設置)的「不可變」引用,並經過調用creator.GetNameSortedEnumerator
或creator.GetIdSortedEnumerator
實現GetEnumerator
。 此類結構的行爲與PersonCollection
的引用很是PersonCollection
,只是它們的GetEnumerator
方法將綁定到PersonCollection
不一樣方法。 也能夠有一個結構包裝一個數組的一部分(例如,一個能夠定義一個ArrayRange<T>
結構,它將保存一個名爲Arr
的T[]
,一個int Offset
和一個int Length
,帶有一個索引屬性,對於一個索引idx
在0到Length-1
的範圍內,將訪問Arr[idx+Offset]
)。 不幸的是,若是foo
是這種結構的只讀實例,當前的編譯器版本將不容許像foo[3]+=4;
由於他們沒法肯定此類操做是否會嘗試寫入foo
字段。 wordpress
也能夠設計一個結構,使其表現得像一個值類型,它保存一個可變大小的集合(每當結構都會被複制時),但惟一的方法就是確保沒有對象。 struct持有一個引用將暴露於任何可能會改變它的東西。 例如,能夠有一個相似於數組的結構,它包含一個私有數組,其索引的「put」方法建立一個新數組,其內容與原始數組的內容相似,除了一個更改的元素。 不幸的是,使這種結構有效地執行可能有些困難。 雖然有時結構語義能夠很方便(例如,可以將相似數組的集合傳遞給例程,而調用者和被調用者都知道外部代碼不會修改集合,可能比要求調用者和調用者更好。 callee防護性地複製他們給出的任何數據,類引用指向永遠不會變異的對象的要求一般是很是嚴格的約束。 函數
.NET支持value types
和reference types
(在Java中,您只能定義引用類型)。 reference types
實例在託管堆中分配,而且在沒有對它們的未完成引用時進行垃圾回收。 另外一方面, value types
實例在stack
中分配,所以一旦其範圍結束,就會回收分配的內存。 固然, value types
經過值傳遞, reference types
經過引用傳遞。 除System.String外,全部C#原始數據類型都是值類型。 性能
什麼時候使用struct over class, 測試
在C#中, structs
是value types
,類是reference types
。 您可使用enum
關鍵字和struct
關鍵字在C#中建立值類型。 使用value type
而不是reference type
將致使託管堆上的對象更少,從而致使垃圾收集器(GC)上的負載更少,GC週期更少,從而提升性能。 可是, value types
也有其缺點。 傳遞一個大struct
確定比傳遞引用更昂貴,這是一個明顯的問題。 另外一個問題是與boxing/unboxing
相關的開銷。 若是您想知道boxing/unboxing
意味着什麼,請按照這些連接獲取有關boxing
和unboxing
說明。 除了性能以外,有時候你只須要類型來得到值語義,若是你只有reference types
,那麼實現它將很是困難(或難看)。 您應該只使用value types
,當您須要複製語義或須要自動初始化時,一般在這些類型的arrays
中。 this
從C#語言規範 : 編碼
1.7結構
與類同樣,結構體是能夠包含數據成員和函數成員的數據結構,但與類不一樣,結構體是值類型,不須要堆分配。 結構類型的變量直接存儲結構的數據,而類類型的變量存儲對動態分配的對象的引用。 結構類型不支持用戶指定的繼承,而且全部結構類型都隱式繼承自類型對象。
結構對於具備值語義的小型數據結構特別有用。 複數,座標系中的點或字典中的鍵值對都是結構的好例子。 對小型數據結構使用結構而不是類可使應用程序執行的內存分配數量產生很大差別。 例如,如下程序建立並初始化100個點的數組。 將Point實現爲類,實例化101個單獨的對象 - 一個用於數組,一個用於100個元素。
class Point { public int x, y; public Point(int x, int y) { this.x = x; this.y = y; } } class Test { static void Main() { Point[] points = new Point[100]; for (int i = 0; i < 100; i++) points[i] = new Point(i, i); } }
另外一種方法是使Point成爲一個結構。
struct Point { public int x, y; public Point(int x, int y) { this.x = x; this.y = y; } }
如今,只實例化一個對象 - 數組的對象 - 而且Point實例以串聯方式存儲在數組中。
使用new運算符調用Struct構造函數,但這並不意味着正在分配內存。 結構構造函數只是返回結構值自己(一般在堆棧的臨時位置),而不是動態分配對象並返回對它的引用,而後根據須要複製該值。
對於類,兩個變量能夠引用同一個對象,所以對一個變量的操做可能會影響另外一個變量引用的對象。 對於結構體,每一個變量都有本身的數據副本,而且一個變量不可能影響另外一個變量。 例如,由如下代碼片斷生成的輸出取決於Point是類仍是結構。
Point a = new Point(10, 10); Point b = a; a.x = 20; Console.WriteLine(b.x);
若是Point是一個類,則輸出爲20,由於a和b引用同一個對象。 若是Point是一個結構,則輸出爲10,由於a到b的賦值會建立該值的副本,而且此副本不受隨後的ax分配的影響
前面的例子強調告終構的兩個侷限性。 首先,複製整個結構一般比複製對象引用效率低,所以對於結構而言,賦值和值參數傳遞可能比使用引用類型更昂貴。 其次,除了ref和out參數以外,不可能建立對結構的引用,結構排除了它們在許多狀況下的使用。
Struct可用於提升垃圾收集性能。 雖然您一般沒必要擔憂GC性能,但有些狀況下它可能會成爲殺手。 就像低延遲應用程序中的大緩存同樣。 請參閱此帖子以獲取示例:
http://00sharp.wordpress.com/2013/07/03/a-case-for-the-struct/
個人規則是
1,始終使用課程;
2,若是存在任何性能問題,我會嘗試根據@IAbstract提到的規則將某些類更改成struct,而後進行測試以查看這些更改是否能夠提升性能。