2012-12-22 288 views
2

微軟已經使用結構如下規則:C#類VS結構

考慮定義一個類的結構,而不是如果 類型的實例是小的和普遍短命或通常嵌入在 其他物體。

不要定義的結構,除非該類型具有所有以下特徵:

  1. 它在邏輯上表示單個值,類似於原始類型(整數,雙,和等等)。
  2. 它的實例大小小於16個字節。
  3. 它是不可變的。
  4. 它不會經常被裝箱。

據我瞭解,你當你想要一個價值型行爲創建結構。當然,這可以讓您在分配和傳遞給函數時複製開銷。但你爲什麼要追隨#2和#3?如果你的價值類型太大了會怎麼樣?此外,我不明白你爲什麼會將不可變類型作爲值類型。如果類型是不可變的,那麼最好通過引用來節省時間,因爲無論如何它都不能被改變。

我問的原因是我在做一個遊戲,其中對象具有像Vector2d類型的座標,速度等屬性。問題是,我應該使Vector2d不可變結構體(不需要大量額外的內存嗎?),可變結構體(人們說它們是邪惡的)或者只是類(我將不得不始終調用vector.Clone(),否則我可能會無意間得到兩個具有相同向量變量的對象)

+2

_「如果你的值類型太大?」_根據MS,你應該使用*類* ... – gdoron

+1

[爲什麼是可變結構邪惡?](http://stackoverflow.com/questions/441309/why-are-mutable-structs-evil) – GSerg

+3

[你應該只根據你面對的實際問題提出實際的,可回答的問題。](http://stackoverflow.com/faq#dontask)那麼你的實際題? –

回答

0

對於#2,不應輕易複製大型結構,因此大部分時間都應該是類。而且,這些並不是硬性規則,只是經驗法則。如果您有充分理由不遵守規則,請繼續。

2

此外,我不明白你爲什麼會將不可變類型作爲值類型。

int類型是不可變的類型,是您爲什麼需要不可變值類型的理想例子。

想象一下,如果int是參考類型。如果您每次使用整數都必須解除引用,那將非常昂貴。事實上,當你使用「盒裝」整數(例如存儲在類型爲object的變量中的整數)時會發生什麼情況。在.NET中與Java相比的一個改進是集合可以容納非盒裝整數。

如果類型是不可變的,你會更好地節省時間供參考

是,如果是大的和不可改變的,那麼你會節省時間通過引用傳遞它傳遞。這就是爲什麼指導方針建議大類型應該是參考類型。

+0

如果有一個int [1]包含值0xBABE1234,則一個線程使用BlockCopy來用0xCE覆蓋第一個字節,而另一個線程使用BlockCopy來覆蓋第二個字節0xFA,使得數組元素現在保存0xBABEFACE,第一個數組元素做了什麼,如果它沒有變異?像0xBABEFACE這樣的值可能是不可變的,但是一個值類型並不真正保存一個值;它包含一組字節並定義這些字節如何解釋爲一個值。 – supercat

-1
  1. 當傳遞/操縱一個結構體時,它的整個值必須在堆棧周圍而不是僅僅引用。一旦它達到一定的大小,16個字節,考慮只使用一個類來避免開銷。

  2. 不變性更多的是旨在減少代碼錯誤的模式,而不是一條硬性規則。如果你的值類型可能是不可變的,那麼可以這樣做。

您可能會誤解不可變性。您的變量可以更改值,但值本身不會更改。例如,您可以擁有一個Datetime變量並將其設置爲任何其他DateTime實例,但實際上在實例初始化後無法更改它們的字段。

+0

如果一個類型應該提供值語義,那麼任何引用類型的實現都必須是不可變的。如果有一個實例並且希望有一個實例幾乎相同,除了「Bar」等於6而不是5,必須創建一個新實例,該實例包含來自舊實例的所有數據的副本(「Bar」除外,新的應該是6)。值類型應該是不可變的想法源於值類型方法應用於只讀實例的方式中的問題。好的解決方案不是製造所謂的「不可變」值類型(實際上不是),而是...... – supercat

+0

......反而認識到如果像「Sphere3d」這樣的類型應該代表四重奏「浮動」 '值,('X','Y','Z'm和'Radius'各一個),這個類型應該只顯示這些值作爲字段;任何使用該類型實例的代碼應該執行相同的驗證,就像它已經分別接收這些參數一樣。對屬性的不必要的包裝可能導致顯着的減速,隨着結構變得更大而變得更糟,並且對導致一些人提出結構應該是不可變的概念的狡詐語義負責。 – supercat

1

16個字節似乎有些隨意,但可能與典型CPU的高速緩存行大小有關。這比現代CPU上的64字節緩存線要小很多。可能是因爲你不能明確地將你的結構對齊到一行。

保持您鍵入不可變再次避免需要通過引用傳遞。而只是返回一個新的實例。以下引用比使用緩存值的成本要高得多,保持較小的值會增加緩存中的機會。

一般來說,如果你想引用語義使它成爲一個類,否則使它成爲一個結構。我建議你遵循MS準則,除非你能證明使用一個分析器(或其他一些經驗證據),否則有很好的理由。

+1

.net框架優化了16個字節和更小的結構的複製,以便複製17個字節的結構將比複製16個字節的結構慢得多。儘管如此,如果一個類型應該表現出值語義並且通常會被分段修改,那麼一個正確使用的暴露字段結構通常可以提供比任何其他類型更好的性能。在某些情況下(例如,分段修改幾乎與常見的一樣 - 如果不是更多的話) - 任何大小的*暴露字段結構將提供比類更好的性能;結構越大,差異越大。 – supercat