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