最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會(huì)員登陸 & 注冊(cè)

第 33 講:面向?qū)ο缶幊蹋ㄎ澹哼\(yùn)算符重載和類型轉(zhuǎn)換器

2021-05-06 08:16 作者:SunnieShine  | 我要投稿

今天我們要說的是類里的兩個(gè)比較重要的成員:運(yùn)算符(Operator)和類型轉(zhuǎn)換器(Cast)。

實(shí)際上類還有三個(gè)成員類型還沒有說:運(yùn)算符、類型轉(zhuǎn)換器和事件(Event),不過因?yàn)槭录@個(gè)成員需要委托類型的依賴,而委托類型我們現(xiàn)在還沒有講,難度也比較大,因此我們只能等到后面才能說了。

Part 1 運(yùn)算符系統(tǒng)和運(yùn)算符重載

要了解運(yùn)算符,就得了解運(yùn)算符在 C# 里的體系架構(gòu)。你可能會(huì)問我,運(yùn)算符不是早就講過了嗎?是的,不過……沒有那么容易。

1-1 運(yùn)算符重載的語法

要知道運(yùn)算符在使用的時(shí)候是有類型、優(yōu)先級(jí)一說。優(yōu)先級(jí)我們并未在之前提到過,因?yàn)橛?jì)算順序一般跟我們?nèi)祟惖挠?jì)算思路和思維是差不多的,因此我們不必去記住這些運(yùn)算符的順序(比如先乘除后加減之類的)。但是,運(yùn)算符實(shí)際上是和數(shù)據(jù)類型綁定的一種概念。這句話是什么意思呢?字符串的加號(hào)是拼接字符串,而數(shù)值的加法是計(jì)算求和的結(jié)果。它們表達(dá)的意義是不同的。在 C# 里,為了幫助我們理解和自定義使用運(yùn)算符的邏輯過程,運(yùn)算符重載的概念就產(chǎn)生了。運(yùn)算符的書寫格式是這樣的:

比如說,字符串的拼接運(yùn)算可通過這樣的語法寫成這樣:

這里用到了 string 的一個(gè)構(gòu)造器。C# 的那些個(gè)值類型是不需要這么書寫代碼的,因?yàn)橹苯佑凶置媪康闹С趾妥兞康馁x值,所以我們基本上碰不到那些構(gòu)造器(實(shí)際上比如說 decimal 類型,就有自己的構(gòu)造器,但我們基本上碰不到它們)。

字符串是一個(gè)特殊的內(nèi)置類型,因?yàn)樗且粋€(gè)引用類型。所謂的引用類型就是內(nèi)存大小不定的、總是以引用進(jìn)行傳遞的數(shù)據(jù)類型。在這個(gè)定義下,所有類聲明出來,一經(jīng)實(shí)例化(new 語句產(chǎn)生了對(duì)象),那么它們就都是引用類型的對(duì)象。而這個(gè)引用類型有一些很特殊的構(gòu)造器,比如說傳入一個(gè) char[],將其轉(zhuǎn)換成一個(gè) string 的字符串實(shí)體。這個(gè)是需要掌握的,當(dāng)然,還有別的傳入寫法,但我們暫時(shí)用不到。

這樣的代碼我們稱為運(yùn)算符重載(Operator Overloading)。這里用的重載和我們實(shí)際上說的方法的重載類似,也有一點(diǎn)不同。畢竟這里的運(yùn)算符重載是基于這里的運(yùn)算符的,所以書寫格式非常詭異。

另外順帶一提,我們需要注意的運(yùn)算符重載有如下的一些規(guī)則:

  • 重載的所有運(yùn)算符,參數(shù)或者返回值的類型必須至少包含這個(gè)類型本身;

  • 重載的運(yùn)算符并非全部都可以,比如 &&、=? :(條件運(yùn)算符) 這類本身就有固定含義的運(yùn)算符就不可重載;

  • 重載的運(yùn)算符有些時(shí)候是配套的,比如 +(加法)在重載之后,那么 += 就自動(dòng)被重載,因?yàn)?a = a + b 里可寫成 a += b,而這個(gè)運(yùn)算符是可翻譯成 + 計(jì)算模式的。因此你實(shí)現(xiàn)了 + 的重載規(guī)則,+= 就不必單獨(dú)寫出來了(實(shí)際上也不讓你單獨(dú)為 += 這樣的復(fù)合賦值運(yùn)算符重載;

  • 重載的運(yùn)算符有些時(shí)候是成對(duì)的,比如 >(大于)運(yùn)算符在重載之后,你就必須要把 <(小于)也一起重載了;==!= 也是;>=<= 也是;

  • 重載的 >>(位右移運(yùn)算符)和 <<(位左移運(yùn)算符)需要傳入兩個(gè)參數(shù),而參數(shù)的右側(cè)必須是一個(gè) int 類型的參數(shù),即你只能寫成比如 public static 類型 operator >>(類型 變量, int 參數(shù))。這個(gè) int 你是不可以隨便換的;

  • 重載的運(yùn)算符必須是 public static 修飾的。

這些規(guī)則需要你記住,因?yàn)樗鼈兗s束了運(yùn)算符不能隨便亂寫和亂用。比如 % 只能是左右兩個(gè)數(shù)值計(jì)算,而你不能改變篡改定義,改成只需要一個(gè)數(shù)就參與數(shù)值計(jì)算。

這么做是有道理的。因?yàn)檫\(yùn)算符本身就不一定非要跟一個(gè)實(shí)體對(duì)象綁定起來,比如加法用的就是兩個(gè)數(shù)值的計(jì)算過程,因此定義成 static 是有道理的;而 public 是因?yàn)椋绻悴槐┞哆\(yùn)算符給外界的話,你還不如不用運(yùn)算符,因?yàn)闆]有意義。當(dāng)初你在設(shè)計(jì)數(shù)據(jù)類型,把它們寫成類的時(shí)候,肯定就是想希望這些東西外部都能用,對(duì)吧;哪有你寫個(gè)運(yùn)算符,結(jié)果只讓類內(nèi)部隨便用,出了類就不能用的道理呢?

盡管約束很多,但我們?nèi)耘f有很多很豐富的選擇和使用。這就是為了保證運(yùn)算符在執(zhí)行的時(shí)候,語義和語法模型不會(huì)變動(dòng)。比如說 +(加號(hào)),就一定是兩個(gè)數(shù)值運(yùn)算。如果你改成了一個(gè)數(shù),加號(hào)就不叫加號(hào)了;改成三個(gè)數(shù)計(jì)算,那么 + 又怎么書寫的問題。運(yùn)算符的優(yōu)先級(jí)是系統(tǒng)規(guī)定的,所以我們不可能通過重載改變這樣的規(guī)則,比如我重載了 +,怎么著它的優(yōu)先級(jí)也必須是在乘除號(hào)之后計(jì)算的,畢竟先乘除后加減的規(guī)則是不可撼動(dòng)的。所以,重載運(yùn)算符僅僅是為了提供一些簡(jiǎn)單的語義模型的拓展,但我們不能篡改語義模型的體系。

這里唯一需要說的重載規(guī)則,就是邏輯元運(yùn)算符。

1-2 邏輯元運(yùn)算符的重載

很奇妙。C# 完全不允許我們重載 &&||,但我們?yōu)榱酥剌d &&||,C# 是提供了這樣的重載機(jī)制的,那就是之前說過的邏輯元運(yùn)算符 truefalse 了。還是需要你注意,這里的 truefalse 不是一個(gè)布爾類型的字面量,而是真正的運(yùn)算符。

還記得我們之前講解邏輯元運(yùn)算的例子嗎?假設(shè)你在開車,開車能過馬路將同時(shí)取決于你的油箱里的油的多少,和紅綠燈的當(dāng)前亮燈的顏色。因?yàn)槲覀冋f油箱油的多少和紅綠燈亮燈的顏色我們都用了一個(gè)叫 Status 的數(shù)據(jù)類型來抽象表示了,那么它應(yīng)該是有三個(gè)數(shù)值的:Green(OK)、Yellow(看起來可以,但有點(diǎn)危險(xiǎn))和 Red(完全不行)。那么,我們?nèi)绻霑鴮懘a的話,我們就可以使用這樣的語法:

假設(shè)我們要測(cè)試這個(gè)類型。

請(qǐng)注意這里的 GetFuelLaunchStatusGetNavigationLaunchStatus 方法,我們并未寫出來,這僅僅表達(dá)的是“獲取油箱油的狀態(tài)”和“紅綠燈狀態(tài)”,然后返回 Status 類型的結(jié)果??梢詮倪@個(gè)代碼里看到,我們直接將 Status 的結(jié)果用 && 連起來了。剛才才說,&& 是不可重載的,可我們?cè)趯?Status 的代碼里,確實(shí)是沒有寫類似 operator && 之類的重載的代碼的,那么怎么這個(gè)代碼就可以運(yùn)行了呢?

之前我們說過,&& 等價(jià)于 false(a) ? a : a & b,所以,我們只需重載 false& 就可以得到 && 的重載規(guī)則的調(diào)用邏輯;同理,|| 等價(jià)于 true(a) ? a : a | b,所以我們只需要重載 true| 就可以得到 || 的調(diào)用邏輯了。所以,我們?yōu)槭裁礇]有重載 &&|| 的語法,就是因?yàn)檫@一點(diǎn)。

C# 團(tuán)隊(duì)這么設(shè)計(jì)語法(不讓重載 &&|| 而是讓你重載 truefalse 這種不是很好理解的運(yùn)算符)是有原因的。還記得我們?cè)谔幚聿紶栴愋偷?truefalse 的計(jì)算規(guī)則嗎?拿 && 來說,如果兩側(cè)的數(shù)值有一個(gè) false,結(jié)果就是 false。那么是不是可以展開 && 的運(yùn)算規(guī)則成 false(a) ? a : a & b 呢?要是 afalsefalse(a) 表達(dá)式成立),那么我們直接取 a 的數(shù)值(false 這個(gè)字面量)作為表達(dá)式結(jié)果;否則,我們就得將 a & b 按照 & 的運(yùn)算規(guī)則計(jì)算出來,把得到的結(jié)果給返回出來。這個(gè)語法保證了 &&|| 運(yùn)算符的短路現(xiàn)象依然在重載運(yùn)算符之后還存在。這下知道為什么 && 里用 false 這個(gè)邏輯元運(yùn)算符了吧:因?yàn)樵诓紶栃捅磉_(dá)式計(jì)算的時(shí)候,本身就是“&& 表達(dá)式里有一方是 false,結(jié)果就會(huì)發(fā)生短路”,這正好就對(duì)應(yīng)了邏輯元運(yùn)算符用的這個(gè) false 符號(hào)。所以它們是相通的。

Part 2 類型轉(zhuǎn)換系統(tǒng)和類型轉(zhuǎn)換器

C# 還有一個(gè)很騷的操作是,它直接允許我們自定義轉(zhuǎn)換器,將當(dāng)前類型直接轉(zhuǎn)換成別的數(shù)據(jù)類型。只要你想,什么類型都可以轉(zhuǎn)。

2-1 強(qiáng)制類型轉(zhuǎn)換器

比如這樣。那么 Status 的實(shí)體對(duì)象在使用的時(shí)候可以寫成 bool condition = (bool)status 的語法。這里的 operator 后面的這個(gè) bool 就是表示 Status 類型的對(duì)象可轉(zhuǎn)換過去的類型。

語法上,我們使用 explicit 關(guān)鍵字來表達(dá)是強(qiáng)制轉(zhuǎn)換。這個(gè)詞很少用到,它在英語里是“必須有的”、“明確的”、“直率的”的意思。比如說例句:

That wasn't an explicit rule in the meeting, but I'm sure that was part of it, you know.

這倒不是在集會(huì)上必有的原則,但是我相信這是其中一個(gè)。

咳咳咳,這個(gè)不是英語課。反正大概是這么一個(gè)詞語。因?yàn)?explicit 關(guān)鍵字意思是“顯式的”,所以 explicit operator 是強(qiáng)制轉(zhuǎn)換的意思。

2-2 隱式類型轉(zhuǎn)換器

比如還是前面這個(gè)例子,我們把 explicit 改成 implicit 即可。這樣的話,類型就允許直接將 Status 類型轉(zhuǎn)換成 bool,比如 bool condition = status 的寫法,你甚至可以不寫 (bool) 這個(gè)強(qiáng)制轉(zhuǎn)換器都行,因?yàn)樗磉_(dá)的是隱式轉(zhuǎn)換。和前面 explicit operator 的寫法類似,operator ?后面緊跟的這個(gè) bool 就是這個(gè) Status 類型可以轉(zhuǎn)換過去的類型。

2-3 轉(zhuǎn)換器和邏輯元運(yùn)算符的重載

前面我們說到了邏輯元運(yùn)算符的重載規(guī)則和語法??赡苣銜?huì)有這樣的疑問。我如果實(shí)現(xiàn)了 Statusbool 類型的隱式轉(zhuǎn)換器的話(比如上面的這個(gè)例子的寫法),那么是不是就意味著我們沒有必要實(shí)現(xiàn)那些個(gè) &、|、truefalse 這四個(gè)運(yùn)算符了???顯然直接一個(gè)隱式轉(zhuǎn)換器就可以解決實(shí)現(xiàn)四個(gè)運(yùn)算符的問題。

實(shí)際上,并不等價(jià)。你可以思考一點(diǎn),在我們舉例說明 Status 這個(gè)類型的實(shí)現(xiàn)規(guī)則的時(shí)候,如果油的狀態(tài)是 Yellow 的時(shí)候,而且紅綠燈也是 Yellow 這個(gè)狀態(tài)的話,按規(guī)則我們得得到 Red 的結(jié)果才對(duì),那么兩個(gè)狀態(tài)的 && 的結(jié)果一定是 false 的;但如果按照隱式轉(zhuǎn)換的規(guī)則,兩個(gè)狀態(tài)全變成 true 了,使得運(yùn)算結(jié)果肯定是 true,因此,并不能這么寫代碼。

Part 3 別在運(yùn)算符重載和類型轉(zhuǎn)換器里拋異常

因?yàn)檫\(yùn)算符和類型轉(zhuǎn)換器的語法規(guī)則比較特殊,所以我們不建議任何使用 C# 的朋友在執(zhí)行的代碼里拋異常。比如說這樣:

這樣實(shí)現(xiàn)代碼雖然嚴(yán)謹(jǐn),但不是良好的代碼實(shí)現(xiàn)(Ill-formed Code)。運(yùn)算符和類型轉(zhuǎn)換器的語法是寫成運(yùn)算符的符號(hào),以及類型轉(zhuǎn)換器的小括號(hào)。如果在里面拋異常的話,比如假設(shè)我們寫 bool condition = status; 這樣的隱式轉(zhuǎn)換語句,如果轉(zhuǎn)換失效,那么顯然 status 這里就會(huì)產(chǎn)生一個(gè)異常。但這僅僅是賦值語句,在別人看來就會(huì)產(chǎn)生困惑:這都哪兒跟哪兒啊,哪有賦值語句拋異常的。所以,bug 產(chǎn)生在這些地方會(huì)很隱蔽。

至此,我們就把類的所有成員都說完了一遍。


第 33 講:面向?qū)ο缶幊蹋ㄎ澹哼\(yùn)算符重載和類型轉(zhuǎn)換器的評(píng)論 (共 條)

分享到微博請(qǐng)遵守國家法律
大荔县| 资阳市| 上栗县| 昌平区| 葫芦岛市| 石嘴山市| 津南区| 漾濞| 浦东新区| 通州区| 旅游| 平度市| 顺义区| 云南省| 安西县| 崇礼县| 陈巴尔虎旗| 肃宁县| 太和县| 徐闻县| 手机| 乳源| 克拉玛依市| 西乌珠穆沁旗| 河东区| 荣成市| 万荣县| 项城市| 德清县| 宜城市| 拉萨市| 封丘县| 抚松县| 新龙县| 云浮市| 南丹县| 若尔盖县| 新昌县| 永胜县| 乌海市| 胶州市|