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

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

第 40 講:面向?qū)ο缶幊蹋ㄊ航涌诘娘@式和隱式實現(xiàn)

2021-05-19 08:04 作者:SunnieShine  | 我要投稿

C# 接口做得非常棒的地方在于,接口分兩種實現(xiàn)模式。它避免了一些復(fù)雜的問題。

Part 1 接口成員的隱式實現(xiàn)

之前我們舉例的時候說明了接口的基本用法。

這種標準的實現(xiàn),稱為接口的隱式實現(xiàn)(Implicit Implementation)。所謂的隱式實現(xiàn),就是“非定向?qū)崿F(xiàn)接口的成員”。因為接口可以實現(xiàn)多個,因此方法可能有非常多。我們?nèi)绻凑漳撤N語法和機制去指定基接口的名字和對應(yīng)的方法名的話,顯然寫起來就很麻煩。因此,我們?yōu)榱吮苊膺@樣的實現(xiàn)過程,我們總是使用隱式實現(xiàn)。

隱式實現(xiàn)也就是非定向?qū)崿F(xiàn)接口的成員。如果接口多起來的話,編譯器也會自動去尋找接口實現(xiàn)過程,然后自動提示你有什么接口成員實現(xiàn)了,哪些又沒有實現(xiàn)。因此隱式實現(xiàn)接口是相當方便的實現(xiàn)模式。

Part 2 接口成員的顯式實現(xiàn)

當然,在極少數(shù)情況下,我們不得不使用顯式實現(xiàn)來避免一些東西。

假設(shè)我們有兩個接口 IAIB,巧就巧在,它們都只有一個接口成員,而且都是方法,而且它們的簽名就差返回值不一樣。假設(shè)它們倆是這樣的:

因為之前說過,只有返回值不同的兩個方法是不構(gòu)成重載的。因此如果我們要實現(xiàn)這兩個接口成員的,所以光靠隱式接口實現(xiàn)是做不到的:

顯然我們肯定會用這樣的方式去實現(xiàn)??蓡栴}就在于,它們倆不構(gòu)成重載,語法是通不過的。這咋辦呢?難道我們就不能用接口了嗎?

其實不是。C# 提供了另外一種實現(xiàn)模式:接口的顯式實現(xiàn)(Explicit Implementation)。

顯式接口實現(xiàn)的語法可能稍微別扭一點:

這里“其它的部分”指的是,接口成員類型對應(yīng)的、需要追加的部分。比如說方法的話,“其它的部分”就包括一對小括號,里面是參數(shù)表列;如果是“屬性”的話,那么“其它的部分”就是一對大括號,然后里面是 get;、set; 或者 get; set; 了。

使用顯式接口實現(xiàn),我們需要先考慮這些不構(gòu)成重載的成員,到底哪個使用起來更多。顯然,decimal 作為返回值類型的這個版本更好一些,可能使用更多一些(畢竟 decimal 類型比 int 類型表達的數(shù)據(jù)范圍更廣),因此我們用 decimal 這個版本的更多。

考慮這個,是因為顯式接口實現(xiàn)是用在“使用情況較少”的那一方的。換句話說,因為 decimal 這個版本用得多,那么我們需要用顯式接口實現(xiàn)的寫法的,是 int 這個版本的。語法如下:

請注意第 9 行代碼。原始寫法 public int SumUp() 被改寫成了 int IA.SumUp()。這就是顯式接口實現(xiàn)的語法。其它的地方則都不發(fā)生任何變動。要改寫的地方只有簽名這一行代碼而已。

顯式接口實現(xiàn)里是不寫訪問修飾符和 abstract 關(guān)鍵字的,想必這一點我也不用說明了吧。不過,override 也是不寫的,因為我們這里給出實現(xiàn),本身就是一種重寫的行為。它和類里的重寫不同:類里的重寫因為可能可以給方法添加 new 修飾符而不是 override 修飾符,因此有兩種可能;而這里只可能是 override


Part 3 類型實現(xiàn)接口下的訪問級別問題

我們來思考一點。雖然在類型的派生關(guān)系下,我們有一個很復(fù)雜的表格來表示所有的級別關(guān)系情況哪些可以那些不行,但接口是不是也遵循這個點呢?實際上接口可以有很多,我可以指定它私下實現(xiàn)一些接口,但不用暴露在外,因此接口比基類類型還要復(fù)雜一些。

首先我們要說一個比較奇特的冷知識。接口是可以嵌套的。雖然我們在程序設(shè)計的時候基本上用不到這個點,所以很少有人知道,但接口確實在 C# 里也可以嵌套;而且,接口里的嵌套類型甚至不一定是接口,還可以是一個類;而普通類型里也可以嵌套一個接口,……啊這。

問題不在這里。我只是想告訴你,既然可以嵌套類型,那么訪問修飾級別就可以有很多情況。

我們先來說一下最簡單的情況,就是都不是嵌套的類型。這也是平時基本上就已經(jīng)夠用了的情況。假設(shè)我類型實現(xiàn)了接口,那么可以有這樣的情況:

  • public class Apublic interface B;

  • public class Ainternal interface B;

  • internal class Apublic interface B;

  • internal class Ainternal interface B

實際上這四種情況全部都可以。其中有一個比較奇怪的繼承關(guān)系,是類型繼承關(guān)系下不可能出現(xiàn)的,但這在接口里是可以被允許的。這類型的接口實現(xiàn)可以在私下自己實現(xiàn),然后不暴露給外界知道我有這一層實現(xiàn)接口的關(guān)系,這就是隱藏接口實現(xiàn)的一個慣用手法:將接口設(shè)置為 internal,然后讓一個 public 類型實現(xiàn)該接口,這樣外界就不知道我這個繼承關(guān)系了。

而如果兩個都是接口的話……

  • public interface Apublic interface B;

  • public interface Ainternal interface B

  • internal interface Apublic interface B;

  • internal interface Ainternal interface B。

這種情況下呢?這個時候它和普通的繼承關(guān)系的約束是一致的,也就是說 public interface J : I 關(guān)系下,JpublicI 接口是 internal 的接口的話,這種關(guān)系是不可以的。

接著我們來討論一下嵌套的情況。

……算了我直接上結(jié)論吧,反正基本上沒有人用得上這種情況……用得上的也只需要查個表就行。

然后是接口和接口的繼承關(guān)系。


Part 4 遺留問題解答

下面我們針對前面介紹的內(nèi)容做一個總結(jié)和說明??赡苣銜邢旅娴膯栴}的困惑,我們都來解答一下。

4-1 為什么不能對接口成員的實現(xiàn)使用 new 修飾符?

要說不能,其實是沒有必要。這是接口的一大性質(zhì):因為接口支持隱式接口實現(xiàn),所以你即使不指明實現(xiàn)的接口名稱是哪個,編譯器自己也知道。因此,override 關(guān)鍵字也就不用寫出來了;我們站在另外一個角度來說的話,既然 override 關(guān)鍵字都不寫了,那么就說明“接口的成員被隱式實現(xiàn)”是一種正常的、默認的行為,因此加 new 修飾符就變得很奇怪:你是在類里給出的實現(xiàn),說明類里沒有同名、同簽名的別的成員。那么,你加上 new 是為了干什么呢?new 是用在同同,就連簽名(如果是方法、索引器或者運算符重載的話,就有簽名一說)都一樣的時候。隱式接口實現(xiàn)暗示了你的類里沒有這樣的情況,所以 new 關(guān)鍵字就顯得沒有意義。

4-2 顯式接口實現(xiàn)僅僅是為了避免不構(gòu)成重載而產(chǎn)生語法錯誤?

顯式接口實現(xiàn)并不是專門用來避免語法錯誤的。它還有一個特性,叫做“隱藏接口成員”。

拿我們前面舉例說明的這個 IASumUp 方法來說吧。我們使用了顯式接口實現(xiàn)來表達 SumUp,這并不僅僅是“為了消除語法錯誤”而這么寫,它還有一個原因是隱藏掉 IA 里的 SumUp 這個成員。

所謂隱藏,和前面介紹過的 new 修飾符還有一點不一樣的感覺。前面說過了,接口可以實現(xiàn)很多個,顯式接口實現(xiàn)要指定接口名稱和實現(xiàn)的接口成員。既然被同時指定了,那么與其認為“這個成員顯式實現(xiàn)在類里”,還不如把它理解成是“這個成員在實例化的時候仍然看不見”。

它的訪問級別最小,小到什么程度呢?小到比 private 還小,因為你甚至就在同一個類型里使用這個成員,都是失敗的。舉個例子。假設(shè),我們在 TestClass 里創(chuàng)建一個 ?Output 方法,它里要輸出一系列數(shù)據(jù)的和:

顯然我們知道 int 作為返回值類型的 SumUp 方法也在這個 TestClass 類里面。但我們就在這個類里使用 SumUp 方法,依舊會產(chǎn)生錯誤。

可以看到,它會告訴你“你沒辦法把 decimal 這個結(jié)果轉(zhuǎn)換為int(你是不是少了一個強制轉(zhuǎn)換?)”。你可能會納悶,我明明有一個 int 返回值的方法 SumUp,怎么告訴我要從 decimal 強制轉(zhuǎn)換過去?因為這個 int 返回值的 SumUp 方法被隱藏掉了,因此編譯器會自動定位到 decimal 的這個方法上去。然后又因為 decimalint 的賦值是需要強制轉(zhuǎn)換的,因此就告知你“decimal 無法轉(zhuǎn)換為 int,請問你是不是少了個強制轉(zhuǎn)換”。

這就是隱藏接口成員的一個特效:隱藏接口成員。這也是為什么我最開始說的這句話:“我們要把不常用的那個方法用顯式接口實現(xiàn)表示出來”的真正原因:因為顯式接口實現(xiàn)會隱藏掉這個成員,導(dǎo)致你無法看到它(它的訪問級別比 private 還要?。?。

不過,這個方法是真的再也看不到了嗎?實際上并不是,這一點我們在下一節(jié)“接口的多態(tài)”里會給大家介紹,把成員轉(zhuǎn)換成接口類型的實例來用的方式;這樣就可以看到這個隱藏成員了。

Part 5 總結(jié)

好久沒見到“總結(jié)”這個部分了。下面我們來對接口內(nèi)容進行一個整理和總結(jié)。

接口可包含屬性、索引器、事件(還沒講)和方法四大成員類型。接口的實現(xiàn)分顯式接口實現(xiàn)和隱式接口實現(xiàn)兩種。一般我們都用的是隱式接口實現(xiàn),因為方便;但是極少數(shù)情況下,接口可能會存在重名但不構(gòu)成重載的現(xiàn)象,這個時候我們需要使用顯式接口實現(xiàn)來避免語法問題。顯式接口實現(xiàn)會隱藏掉成員,所以請盡量使用隱式接口實現(xiàn)的模式,除非是迫不得已出現(xiàn)上面這樣的情況。


第 40 講:面向?qū)ο缶幊蹋ㄊ航涌诘娘@式和隱式實現(xiàn)的評論 (共 條)

分享到微博請遵守國家法律
新营市| 澜沧| 高要市| 同德县| 于田县| 丹寨县| 买车| 盘锦市| 渭源县| 临桂县| 金山区| 渭源县| 牟定县| 游戏| 峨山| 宁南县| 漠河县| 连云港市| 大安市| 裕民县| 阳谷县| 喀喇| 磐安县| 临澧县| 方城县| 潞城市| 南和县| 萍乡市| 肥城市| 宜春市| 绵竹市| 繁昌县| 句容市| 满洲里市| 浦北县| 庆阳市| 额敏县| 奇台县| 南江县| 清徐县| 卢湾区|