<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          如何在 C# 8 中使用默認(rèn)接口方法

          共 4321字,需瀏覽 9分鐘

           ·

          2021-02-10 23:20

          C# 8 中新增了一個(gè)非常有趣的特性,叫做 默認(rèn)接口方法 (又稱虛擬擴(kuò)展方法),這篇文章將會討論 C# 8 中的默認(rèn)接口方法以及如何使用。

          在 C# 8 之前,接口不能包含方法定義,只能在接口中定義方法簽名,還有一個(gè)就是接口的成員默認(rèn)是 public 和 abstract , 在 C# 8 之前,接口不能包含字段,也不能包含private, protected, 或者 internal 的方法成員。如果你在接口中引入了一個(gè)新成員,默認(rèn)情況下你必須更新實(shí)現(xiàn)該接口的所有子類。

          在 C# 8 中可以在接口定義方法的默認(rèn)實(shí)現(xiàn),而且還可以定義接口成員為 private,protect,甚至是 static,還有一點(diǎn)挺奇葩的,一個(gè)接口的 protect 成員是不能被實(shí)現(xiàn)類所訪問的,相反,它只能在子接口中被訪問,接口的 virtual 成員可以由派生接口 override,但不能被派生類 override,還有一點(diǎn)請注意,接口目前還不能定義 實(shí)例成員

          為什么要使用默認(rèn)接口方法

          所謂的 默認(rèn)接口方法 指的是接口中定義了一個(gè)默認(rèn)實(shí)現(xiàn)的方法, 如果實(shí)現(xiàn)該接口的類沒有實(shí)現(xiàn)默認(rèn)接口方法的話,那么這個(gè) 默認(rèn)接口方法 只能從接口上進(jìn)行訪問,這是一個(gè)很有用的特性,因?yàn)樗梢詭椭_發(fā)人員在不破壞現(xiàn)有功能的情況下向接口的未來版本添加新方法。

          考慮下面的 ILogger 定義。


          ????public?interface?ILogger
          ????{
          ????????public?void?Log(string?message);
          ????}

          下面的兩個(gè)類擴(kuò)展了ILogger接口并實(shí)現(xiàn)了Log()方法。


          ????public?class?FileLogger?:?ILogger
          ????{
          ????????public?void?Log(string?message)
          ????????{
          ????????????//Some?code
          ????????}
          ????}

          ????public?class?DbLogger?:?ILogger
          ????{
          ????????public?void?Log(string?message)
          ????????{
          ????????????//Some?code
          ????????}
          ????}

          現(xiàn)在假設(shè)你想在ILogger接口中新增一個(gè)方法,該方法接受兩個(gè)參數(shù):一個(gè) 文本 一個(gè) 日志級別,下面的代碼片段展示了日志級別的枚舉類。


          ????public?enum?LogLevel
          ????{
          ????????Info,?Debug,?Warning,?Error
          ????}

          修改后的 ILogger 接口如下:


          ????public?interface?ILogger
          ????{
          ????????public?void?Log(string?message);
          ????????public?void?Log(string?message,?LogLevel?logLevel);
          ????}

          好了,現(xiàn)在問題來了,因?yàn)?ILogger 中新增了一個(gè) Log 方法,你必須要在所有實(shí)現(xiàn)該接口的所有子類中實(shí)現(xiàn) Log(string message, LogLevel logLevel) 方法,這就很尷尬了,如果不這樣做的話,編譯器肯定是不會放行的,在現(xiàn)實(shí)情況下,這個(gè)接口實(shí)現(xiàn)類可能在多個(gè) dll 中,甚至在多個(gè)團(tuán)隊(duì)中,可想而知,這個(gè)工作量是非常大并且非常痛苦的。

          默認(rèn)接口方法案例

          這就是 默認(rèn)接口方法 的應(yīng)用場景,你可以在接口中定義一個(gè)默認(rèn)方法是實(shí)現(xiàn),如下代碼所示:


          ????public?interface?ILogger
          ????{
          ????????public?void?Log(string?message);

          ????????public?void?Log(string?message,?LogLevel?logLevel)
          ????????{
          ????????????Console.WriteLine("Log?method?of?ILogger?called.");
          ????????????Console.WriteLine("Log?Level:?"+?logLevel.ToString());
          ????????????Console.WriteLine(message);
          ????????}
          ????}

          這個(gè)時(shí)候,實(shí)現(xiàn) ILogger 接口的子類可以不實(shí)現(xiàn)新的 Log(string message, LogLevel logLevel) 方法,因此下面的代碼也是跑的通的,編譯器不會拋出任何錯(cuò)誤。


          ????public?class?FileLogger?:?ILogger
          ????{
          ????????public?void?Log(string?message)
          ????????{
          ????????????//Some?code
          ????????}
          ????}

          ????public?class?DbLogger?:?ILogger
          ????{
          ????????public?void?Log(string?message)
          ????????{
          ????????????//Some?code
          ????????}
          ????}

          默認(rèn)接口方法不能被繼承

          現(xiàn)在創(chuàng)建一個(gè) FileLogger 類實(shí)例,然后直接調(diào)用新的帶參數(shù)的 Log() 方法,如下代碼所示:


          FileLogger?fileLogger?=?new?FileLogger();
          fileLogger.Log("This?is?a?test?message.",?LogLevel.Debug);

          從上面圖可看出 默認(rèn)接口方法 不能被子類繼承,換句話說,子類根本就不知道接口中還有帶參數(shù)的 Log() 方法。

          默認(rèn)接口方法和菱形問題

          現(xiàn)在有一個(gè)非常重要的問題,默認(rèn)接口方法如何避免 菱形問題?換句話說就是 接口的 多繼承 問題,考慮下面的代碼清單。


          ????public?interface?A
          ????{
          ????????public?void?Display();
          ????}

          ????public?interface?B?:?A
          ????{
          ????????public?void?Display()
          ????????{
          ????????????Console.WriteLine("Interface?B.");
          ????????}
          ????}

          ????public?interface?C?:?A
          ????{
          ????????public?void?Display()
          ????????{
          ????????????Console.WriteLine("Interface?C.");
          ????????}
          ????}

          ????public?class?MyClass?:?B,?C
          ????{

          ????}

          當(dāng)編譯上面代碼時(shí),會拋出一個(gè)編譯錯(cuò)誤,說 MyClass 沒有實(shí)現(xiàn) A.Display() 方法,解決這個(gè)問題很簡單,在 MyClass 中實(shí)現(xiàn)一下接口方法就可以了,如下代碼所示:


          ????public?interface?A
          ????{
          ????????public?void?Display();
          ????}
          ????public?interface?B?:?A
          ????{
          ????????public?void?Display()
          ????????{
          ????????????Console.WriteLine("Interface?B.");
          ????????}
          ????}
          ????public?interface?C?:?A
          ????{
          ????????public?void?Display()
          ????????{
          ????????????Console.WriteLine("Interface?C.");
          ????????}
          ????}
          ????public?class?MyClass?:?B,?C
          ????{
          ????????public?void?Display()
          ????????{
          ????????????Console.WriteLine("MyClass.");
          ????????}
          ????}

          接下來就可以生成 MyClass 實(shí)例了,然后再調(diào)用 Display() 方法,如下代碼所示:


          ????????static?void?Main(string[]?args)
          ????????{
          ????????????A?obj?=?new?MyClass();
          ????????????obj.Display();
          ????????????Console.Read();
          ????????}

          現(xiàn)在問題來了,到底是哪一個(gè) Display() 方法被調(diào)用了呢?為了避免歧義,C# 將會使用最近覆蓋規(guī)則,即 Class.Display() 方法被最先調(diào)用。

          抽象類 VS 接口

          到這里,我想你肯定有疑問,抽象類接口 是不是很相似了,甚至可以互換了?雖然抽象類和接口現(xiàn)在看起來在很多方面都很相似,但兩者之間還是有微妙的區(qū)別的,具體如下:

          • 抽象類可以有實(shí)例成員,接口則不能。

          • 抽象類不能多繼承,接口還是可以的。

          默認(rèn)接口方法 允許開發(fā)人員利用 trait 編程技術(shù),該技術(shù)可以讓那些附屬于該方法的不相關(guān)類型得以繼續(xù)使用,可能你有點(diǎn)懵,我舉個(gè)例子:假設(shè)你構(gòu)建好了一個(gè)dll,被很多的開發(fā)人員所使用,現(xiàn)在你要發(fā)布該 dll 的新版本,比如說往接口中添加了新方法,這個(gè)時(shí)候你可以定義默認(rèn)實(shí)現(xiàn),這樣就可以對已使用的開發(fā)者進(jìn)行無感升級。

          譯文鏈接:https://www.infoworld.com/article/3455239/how-to-use-default-interface-methods-in-csharp-8.html

          回復(fù)?【關(guān)閉】學(xué)關(guān)
          回復(fù)?【實(shí)戰(zhàn)】獲取20套實(shí)戰(zhàn)源碼
          回復(fù)?【被刪】學(xué)個(gè)
          回復(fù)?【訪客】學(xué)
          回復(fù)?【小程序】學(xué)獲取15套【入門+實(shí)戰(zhàn)+賺錢】小程序源碼
          回復(fù)?【python】學(xué)微獲取全套0基礎(chǔ)Python知識手冊
          回復(fù)?【2019】獲取2019 .NET 開發(fā)者峰會資料PPT
          回復(fù)?【加群】加入dotnet微信交流群

          對抗流氓app開屏廣告,你需要這款神器!


          臥槽又來一個(gè)神器,可以查看微信朋友圈訪客記錄!


          瀏覽 24
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  免费在线观看黄视频 | 无码有码一区 | 精品国视频| 成人高潮AA 毛片 | 最新av|