c# types



ValueTypes如何從Object(ReferenceType)派生而仍然是ValueTypes? (4)

C#不允許從類派生結構

你的陳述不正確,因此你的困惑。 C#允許結構派生自類。 所有結構派生自同一個類System.ValueType,它派生自System.Object。 所有枚舉都來自System.Enum。

更新:一些(現已刪除)評論中存在一些混淆,需要澄清。 我會問一些其他問題:

結構是否來自基類型?

顯然是的。 我們可以通過閱讀規範的第一頁看到這一點:

所有C#類型(包括int和double等基本類型)都從單個根對像類型繼承。

現在,我注意到規範誇大了這裡的情況。 指針類型不是從對象派生的,並且接口類型和類型參數類型的派生關係比此草圖指示的更複雜。 但是,顯然所有結構類型都是從基類型派生的。

還有其他方法我們知道結構類型派生自基類型嗎?

當然。 結構類型可以覆蓋ToString 。 什麼是覆蓋,如果不是它的基本類型的虛方法? 因此它必須具有基本類型。 那個基類型是一個類。

我可以從我選擇的類派生用戶定義的結構嗎?

顯然沒有。 這並不意味著結構不是來自一個類 。 結構派生自一個類,從而繼承該類的可遺傳成員。 實際上,結構需要從特定類派生: Enum需要從Enum派生,結構需要從ValueType派生。 因為這些是必需的 ,所以C#語言禁止在代碼中聲明派生關係。

為什麼要禁止呢?

當需要關係 ,語言設計者可以選擇:(1)要求用戶鍵入所需的咒語,(2)使其成為可選項,或(3)禁止它。 每個都有優點和缺點,C#語言設計師根據每個的具體細節選擇不同。

例如,const字段必須是靜態的,但是禁止說它們是因為這樣做是第一次,毫無意義的措辭,其次,暗示有非靜態const字段。 但是,即使開發人員別無選擇,也需要將重載運算符標記為靜態; 開發人員很容易相信運算符重載是一種實例方法。 這超越了用戶可能會認為“靜態”意味著“虛擬”也是可能性的擔憂。

在這種情況下,要求用戶說他們的結構派生自ValueType似乎只是過多的措辭,並且它暗示結構可以從另一種類型派生。 為了消除這兩個問題,C#規定在結構派生自基類型的代碼中聲明是非法的 ,儘管它確實如此。

類似地,所有委託類型都派生自MulticastDelegate ,但C#要求您要這樣做。

所以,現在我們已經確定C#中的所有結構都來自一個類

從類中 繼承派生之間的關係是什麼?

許多人對C#中的繼承關係感到困惑。 繼承關係非常簡單:如果結構,類或委託類型D派生自類型B,那麼B的可遺傳成員也是D的成員。就這麼簡單。

當我們說結構派生自ValueType時,對繼承有什麼意義? 簡單地說,ValueType的所有可遺傳成員也是結構的成員。 例如,這就是結構體獲取ToString實現的方式; 它繼承自struct的基類。

所有遺產成員? 當然不是。 私人會員是否可以遺傳?

是。 基類的所有私有成員也是派生類型的成員。 如果呼叫站點不在該成員的可訪問域中 ,則通過名稱呼叫這些成員是非法的。 僅僅因為你有一個成員並不意味著你可以使用它!

我們現在繼續原來的答案:

CLR如何處理這個問題?

非常好。 :-)

使值類型成為值類型的原因是它的實例是按值複製的 。 使引用類型成為引用類型的原因是它的實例是通過引用複制的 。 您似乎有一些信念認為值類型和引用類型之間的繼承關係在某種程度上是特殊和不尋常的,但我不明白這種信念是什麼。 繼承與事物的複制方式無關。

以這種方式看待它。 假設我告訴你以下事實:

  • 有兩種盒子,紅盒子和藍盒子。

  • 每個紅色框都是空的。

  • 有三個特殊的藍色方框,分別叫做O,V和E.

  • O不在任何盒子裡面。

  • V在O裡面。

  • E在V裡面

  • V裡面沒有其他藍盒子。

  • E內沒有藍框。

  • 每個紅色框都在V或E中。

  • 除O之外的每個藍色框本身都在藍色框內。

藍色框是引用類型,紅色框是值類型,O是System.Object,V是System.ValueType,E是System.Enum,“內部”關係是“派生自”。

這是一套完全一致且簡單的規則,如果您有大量的紙板和耐心,您可以輕鬆實現這些規則。 盒子是紅色還是藍色與內部無關; 在現實世界中,完全可以在藍色框內放置一個紅色框。 在CLR中,創建一個繼承自引用類型的值類型是完全合法的,只要它是System.ValueType或System.Enum即可。

那麼讓我們改一下你的問題:

ValueTypes如何從Object(ReferenceType)派生而仍然是ValueTypes?

每個紅色框(值類型)是如何在內部(派生自)框O(System.Object),它是一個藍色框(參考類型)並且仍然是一個紅色框(值類型)?

當你這樣說時,我希望這很明顯。 沒有什麼可以阻止你在盒子V裡放一個紅色盒子,盒子裡面是藍色的盒子。 為什麼會這樣?

額外更新:

Joan最初的問題是關於值類型如何從引用類型派生。 我的原始答案並沒有真正解釋CLR使用的任何機制來解釋我們在兩個具有完全不同表示的事物之間存在推導關係的事實 - 即,所引用的數據是否具有對像頭,同步塊,是否為垃圾收集目的擁有自己的存儲,等等。 這些機制很複雜,太複雜,無法在一個答案中解釋。 CLR類型系統的規則比我們在C#中看到的稍微簡化的風格要復雜得多,例如,在類型的盒裝版本和非盒裝版本之間沒有明顯的區別。 泛型的引入也導致了大量額外的複雜性被添加到CLR中。 有關詳細信息,請參閱CLI規範,特別注意裝箱和受限虛擬調用的規則。

C#不允許從類派生結構,但所有ValueType都派生自Object。 這種區別在哪裡?

CLR如何處理這個問題?


Answer #1

你的陳述不正確,因此你的困惑。 C#允許結構派生自類。 所有結構都派生自同一個類System.ValueType

所以讓我們試試這個:

 struct MyStruct :  System.ValueType
 {
 }

這甚至都不會編譯。 編譯器會提醒您“接口列表中的類型'System.ValueType'不是接口”。

反編譯作為結構的Int32時,您會發現:

public struct Int32:IComparable,IFormattable,IConvertible {},不提及它派生自System.ValueType。 但是在對象瀏覽器中,您確實發現Int32繼承自System.ValueType。

所以這些讓我相信:

我認為回答這個問題的最好方法是ValueType很特別。 它本質上是CLR類型系統中所有值類型的基類。 很難知道如何回答“CLR如何處理這個問題”,因為它只是CLR的一個規則。


Answer #2

盒裝值類型實際上是一種引用類型(它像一個一樣行走,像一個一樣嘎嘎叫,所以實際上就是一個)。 我建議ValueType實際上不是值類型的基本類型,而是在轉換為Object類型時可以轉換值類型的基本引用類型。 非盒裝值類型本身位於對象層次結構之外。


Answer #3

這是由CLR維護的一種有點人為的構造,以便允許將所有類型視為System.Object。

值類型派生自System.Object到System.ValueType ,這是特殊處理髮生的地方(即:CLR處理從ValueType派生的任何類型的裝箱/取消裝箱等)。





reference-type