C#不允許從類派生結(jié)構(gòu)
你的說法不正確,所以你很困惑。C#是嗎?允許結(jié)構(gòu)從類派生。所有結(jié)構(gòu)都來自同一個類System.ValueType,該類派生于System.Object。所有枚舉都來自System.Enum。
更新:在一些(現(xiàn)在刪除的)評論中出現(xiàn)了一些混亂,需要澄清。我再問幾個問題:
結(jié)構(gòu)是從基類型派生的嗎?
顯然是的。通過閱讀規(guī)范的第一頁,我們可以看到這一點:
所有C#類型,包括int和Double等基元類型,都是從單個根對象類型繼承的。
現(xiàn)在,我注意到規(guī)范夸大了這里的情況。指針類型不是從對象派生的,接口類型和類型參數(shù)類型的派生關(guān)系比此草圖所指示的要復(fù)雜得多。但是,很明顯,所有的struct類型都是從基類型派生的。
我們是否有其他方法知道結(jié)構(gòu)類型是從基類型派生出來的?
好的。結(jié)構(gòu)類型可以覆蓋ToString
..如果不是它的基本類型的虛擬方法,它將覆蓋什么?因此,它必須有一個基類型。這個基類型是一個類。
我可以從我選擇的類中派生出用戶定義的結(jié)構(gòu)嗎?
顯然沒有。這并不意味著結(jié)構(gòu)不是從類派生的。..結(jié)構(gòu)派生自類,從而繼承該類的可遺傳成員。實際上,結(jié)構(gòu)是所需從特定類派生:枚舉必須從Enum
,則需要從ValueType
..因為這些是所需,C#語言禁止您可以從代碼中說明派生關(guān)系。
為什么要禁止?
當一段關(guān)系所需,語言設(shè)計器有以下選項:(1)要求用戶鍵入所需的咒語,(2)使其可選,或(3)禁止使用。每個設(shè)計人員各有優(yōu)缺點,C#語言設(shè)計人員根據(jù)每個設(shè)計人員的具體細節(jié)做出不同的選擇。
例如,Const字段被要求是靜態(tài)的,但是禁止說它們是靜態(tài)的,因為這樣做首先是沒有意義的語句,其次,意味著存在非靜態(tài)Const字段。但是,重載操作符必須標記為靜態(tài)的,即使開發(fā)人員別無選擇;開發(fā)人員很容易認為操作符重載是一個實例方法。這壓倒了用戶可能會相信“靜態(tài)”意味著,比如說“虛擬”也是一種可能性的擔憂。
在這種情況下,要求用戶說他們的結(jié)構(gòu)是從ValueType派生的,這看起來僅僅是多余的語句,這意味著結(jié)構(gòu)能派生自另一種類型。為了消除這兩個問題,C#制作了它非法在代碼中聲明結(jié)構(gòu)是從基類型派生的,盡管它顯然是從基類型派生的。
類似地,所有委托類型都派生自MulticastDelegate
,但C#要求你不說出來。
所以,現(xiàn)在我們已經(jīng)確定C#中的所有結(jié)構(gòu)都是從一個類派生出來的。.
之間的關(guān)系是什么?繼承和從類派生?
許多人對C#中的繼承關(guān)系感到困惑。繼承關(guān)系非常簡單:如果結(jié)構(gòu)、類或委托類型D來自類型B,則B的可遺傳成員也是D的成員。
當我們說一個結(jié)構(gòu)從ValueType派生出來時,它對繼承意味著什么?簡單地說,ValueType的所有可遺傳成員也都是結(jié)構(gòu)的成員。結(jié)構(gòu)是如何獲得它們的實現(xiàn)的。ToString
例如,它是從結(jié)構(gòu)的基類繼承的。
所有可遺傳的成員?當然不是。私人成員可以遺傳嗎?
是。基類的所有私有成員也是派生類型的成員。當然,如果調(diào)用站點不在可達域那個成員。僅僅因為你有一個會員并不意味著你可以使用它!
我們現(xiàn)在繼續(xù)原來的答覆:
CLR如何處理這個問題?
非常好。*-)
使值類型的原因是它的實例是按值復(fù)制..使引用類型的原因是它的實例是引用復(fù)制..你似乎相信繼承價值類型和引用類型之間的關(guān)系在某種程度上是特殊和不尋常的,但我不明白這種信念是什么。繼承與復(fù)制事物的方式無關(guān)。
從這邊看。假設(shè)我告訴你以下事實:
藍色框是引用類型,紅色框是值類型,O是System.Object,V是System.ValueType,E是System.Enum,“內(nèi)部”關(guān)系是“派生的”。
如果你有大量的紙板和耐心,這是一套完全一致而又直截了當?shù)囊?guī)則,如果你有大量的紙板和耐心,你可以很容易地實現(xiàn)它。一個盒子是紅色的還是藍色的與它的內(nèi)部無關(guān);在現(xiàn)實世界中,把一個紅色的盒子放進一個藍色的盒子里是完全可能的。在CLR中,創(chuàng)建從引用類型繼承的值類型是完全合法的,只要它是System.ValueType或System.Enum。
讓我們重新表述一下你的問題:
ValueTypes是如何從對象(引用類型)派生而仍然是ValueTypes的?
如
如何使每個紅色框(值類型)都在(派生自)方框O(System.Object)中,該框是藍色框(引用類型),但仍然是紅色框(值類型)?
當你這樣說的時候,我希望這是顯而易見的。沒有什么能阻止你把一個紅色的盒子放進盒子V里面,它在盒子O里面,是藍色的。為什么會有?
另一項最新情況:
瓊最初的問題是關(guān)于它是怎樣的可能值類型派生自引用類型。我最初的回答并沒有真正解釋CLR使用的任何機制來解釋這樣一個事實,即我們在兩件事之間有一個派生關(guān)系-即所引用的數(shù)據(jù)是否有一個對象頭、一個同步塊、它是否擁有自己的用于垃圾收集的存儲,等等。這些機制很復(fù)雜,太復(fù)雜,無法用一個答案來解釋。CLR類型系統(tǒng)的規(guī)則比我們在C#中看到的稍微簡單的風(fēng)格要復(fù)雜得多,例如,在C#中,類型的裝箱版本和未裝箱版本之間沒有很大的區(qū)別。泛型的引入也給CLR增加了許多額外的復(fù)雜性。有關(guān)詳細信息,請參閱CLI規(guī)范,特別注意裝箱規(guī)則和受限的虛擬調(diào)用。