主頁 > .NET開發 > C#8.0之后介面已經不再單純了,我懵逼了!

C#8.0之后介面已經不再單純了,我懵逼了!

2020-10-24 09:44:30 .NET開發

一:背景

1. 講故事

大家在經過面向物件洗禮的時候,都了解過介面,而且知道它是一種自上而下的設計思路,舉個例子,我們電腦上都有 USB 2.0 介面,藍牙耳機實作了它可以進行充電,移動硬碟實作了它可以在電腦端顯示硬碟內容,藍牙滑鼠實作了它可以進行滑鼠操控,可以看出USB插口做出來后,誰來實作誰也搞不清楚,實作者能做出什么東西,誰也不知道,這就是介面的魅力,落實在 C# 上就是介面中那一個一個的 stub 方法,留給未來的有緣人去實作,如下代碼:


    public interface IUsb
    {
        void Execute();
    }

2. 你可能會有的疑惑

有些朋友可能會說,碼農胡言亂語,介面不光可以定義實體方法,還可以定義 屬性,索引器,事件 等等,,, 如下代碼:


    public interface IUsb
    {
        event Action<string> action;

        string Name { get; set; }

        string this[string key]
        {
            get; set;
        }

        void Execute();
    }

哈哈,果然是一個好問題,沒錯,屬性,索引器和事件都可以定義在介面中,但請不要忘了,你列舉的這些都是編譯器層面的語法糖而已,言外之意就是你看過 編譯后的 IL 代碼嗎? 如下圖所示:

可以看到,那些所謂的語法糖在IL層面統統是方法,這就很好的解釋了為啥介面中只能定義方法的原因,

3. 現在的介面真的變了

然而這種平衡在 C# 8.0 中被打破,現如今的介面除了常規的實體方法,還可以定義任何標記為 static 的欄位,屬性,方法,建構式 甚至還可以是 實體方法的默認實作,這就很奇葩了,,,不得不大吼一聲,????, 參考代碼如下:


    public interface IUsb
    {
        //常量
        public const string constVal = "";

        //靜態欄位
        public static int age = 20;

        //靜態建構式
        static IUsb() { }

        //默認方法實作
        void Disco() { Console.WriteLine("Disco..."); }

        void Execute();
    }

這下把我搞蒙了,目前除了一些實體欄位還不能定義外,其他的都沒有問題了,我相信不久的將來 interface 也會把這個遺憾解決掉,/(ㄒoㄒ)/~~ , 這叫我如何向后來的晚輩解釋呀~~~ 搞的我現在有很多疑惑!

二:筆者的疑惑

1. 介面的默認方法意義何在?

一個事物的出現,必然有它的應用場景,有些朋友可能會談到這樣的場景,當很多類實作了 IUSB 介面之后,如下代碼:


    public interface IUsb
    {
        void Execute();
    }

    public class Mp4 : IUsb
    {
        public void Execute() { }
    }

    public class Mouse: IUsb
    {
        public void Execute(){ }
    }

由于某些原因我準備在 IUSB 中新增 Disco 方法,這個時候 MP4 和 Mouse 類肯定會報錯,大家都知道這是因為沒有實作 Disco 的方法,如下圖所示:

這個時候該怎么辦呢? C# 8.0 的介面默認方法就起到作用了,可以直接在原有介面中定義默認方法,對眾多的介面實作者們是無感知的,可以編譯成功,如下圖所示:

一起都很順利,接下來我就迫不及待的呼叫 Disco 方法,代碼如下:

我去,從圖中看居然說 Mp4 類沒有 Disco 方法,這就很莫名其妙了,氣人,這叫啥默認方法,為了驗證 MP4 類到底有沒有 Disco 方法,一個到位的驗證方式就是用 windbg 看看 MP4 的方法表,


0:000> !do 0x0000021e63c2ab10
Name:        DataStruct.Mp4
MethodTable: 00007ff7cd972248
EEClass:     00007ff7cd96c5e8
Size:        24(0x18) bytes
File:        E:\net5\ConsoleApp2\ConsoleApp1\bin\Debug\netcoreapp3.1\ConsoleApp1.dll
Fields:
None
0:000> !dumpmt -md 00007ff7cd972248
EEClass:         00007FF7CD96C5E8
Module:          00007FF7CD94F7D0
Name:            DataStruct.Mp4
mdToken:         0000000002000004
File:            E:\net5\ConsoleApp2\ConsoleApp1\bin\Debug\netcoreapp3.1\ConsoleApp1.dll
BaseSize:        0x18
ComponentSize:   0x0
Slots in VTable: 6
Number of IFaces in IFaceMap: 1
--------------------------------------
MethodDesc Table
           Entry       MethodDesc    JIT Name
00007FF7CD8A0090 00007FF7CD870A78   NONE System.Object.Finalize()
00007FF7CD8A0098 00007FF7CD870A88   NONE System.Object.ToString()
00007FF7CD8A00A0 00007FF7CD870A98   NONE System.Object.Equals(System.Object)
00007FF7CD8A00B8 00007FF7CD870AD8   NONE System.Object.GetHashCode()
00007FF7CD8B0670 00007FF7CD972228   NONE DataStruct.Mp4.Execute()
00007FF7CD8B1030 00007FF7CD972238    JIT DataStruct.Mp4..ctor()

從上面最后6行代碼可看出,MP4類的方法表中根本就沒有 Disco 方法,說明 MP4 的世界里根本就沒有這玩意,,,那怎么樣才能呼叫的上呢?你需要將 mp4 轉成 IUSB 介面,然后再呼叫 Disco 方法就可以了,如下圖所示:

可是即使能運行,又有什么用呢?反正子類是感知不到這個介面的默認方法,也顛覆了對介面的認知!我是沒有看出有什么好處,水平有限沒辦法哈,,,

2. 這個場景自有它的解決方案 [擴展方法]

剛才有些朋友提到的場景說后續增加介面方法的時候不影響已實作子類修改代碼,其實不需要這個特性 C# 也能實作,畢竟這么龐大的類別庫代碼,肯定會有這樣的場景哈,我就拿 List 集合說事,如下代碼是 List 的類定義:


public class List<T> :IList<T>, ICollection<T>
{
}

public interface IList<T> : ICollection<T>, IEnumerable<T>, IEnumerable
{
	int IndexOf(T item);

	void Insert(int index, T item);

	void RemoveAt(int index);
}

public interface ICollection<T> : IEnumerable<T>, IEnumerable
{
	void Add(T item);

	void Clear();

	bool Contains(T item);

	void CopyTo(T[] array, int arrayIndex);

	bool Remove(T item);
}

可以看到 List 實作了 IList 和 ICollection 共 7 個方法,但大家在用 List 編碼的時候發現其實遠不止這 7 個方法,其他方法的接入(Select,Where)就是通過 C# 特有的 擴展方法 機制實作的,對不對,我覺得擴展方法就可以很好的解決 默認介面方法 的問題,所以 USB 介面可以用 擴展方法 來實作,如下代碼所示:


    static void Main(string[] args)
    {
         var mp4 = new Mp4();

         mp4.Disco();

        Console.ReadLine();
    }

    public static class UsbExtension
    {
        public static void Disco(this IUsb usb)
        {
            Console.WriteLine("Disco...");
        }
    }

三: 總結

總的來說,這是一個顛覆我三觀的特性,破壞了我對介面的認知,不想再說什么了,大家有什么妙解,歡迎留言~~~

更多高質量干貨:參見我的 GitHub: dotnetfly

圖片名稱

轉載請註明出處,本文鏈接:https://www.uj5u.com/net/188601.html

標籤:.NET技术

上一篇:C#8.0之后介面已經不再單純了,我懵逼了!

下一篇:VS擴展CodeMaid代碼整理插件

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • WebAPI簡介

    Web體系結構: 有三個核心:資源(resource),URL(統一資源識別符號)和表示 他們的關系是這樣的:一個資源由一個URL進行標識,HTTP客戶端使用URL定位資源,表示是從資源回傳資料,媒體型別是資源回傳的資料格式。 接下來我們說下HTTP. HTTP協議的系統是一種無狀態的方式,使用請求/ ......

    uj5u.com 2020-09-09 22:07:47 more
  • asp.net core 3.1 入口:Program.cs中的Main函式

    本文分析Program.cs 中Main()函式中代碼的運行順序分析asp.net core程式的啟動,重點不是剖析原始碼,而是理清程式開始時執行的順序。到呼叫了哪些實體,哪些法方。asp.net core 3.1 的程式入口在專案Program.cs檔案里,如下。ususing System; us ......

    uj5u.com 2020-09-09 22:07:49 more
  • asp.net網站作為websocket服務端的應用該如何寫

    最近被websocket的一個問題困擾了很久,有一個需求是在web網站中搭建websocket服務。客戶端通過網頁與服務器建立連接,然后服務器根據ip給客戶端網頁發送資訊。 其實,這個需求并不難,只是剛開始對websocket的內容不太了解。上網搜索了一下,有通過asp.net core 實作的、有 ......

    uj5u.com 2020-09-09 22:08:02 more
  • ASP.NET 開源匯入匯出庫Magicodes.IE Docker中使用

    Magicodes.IE在Docker中使用 更新歷史 2019.02.13 【Nuget】版本更新到2.0.2 【匯入】修復單列匯入的Bug,單元測驗“OneColumnImporter_Test”。問題見(https://github.com/dotnetcore/Magicodes.IE/is ......

    uj5u.com 2020-09-09 22:08:05 more
  • 在webform中使用ajax

    如果你用過Asp.net webform, 說明你也算是.NET 開發的老兵了。WEBform應該是2011 2013左右,當時還用visual studio 2005、 visual studio 2008。后來基本都用的是MVC。 如果是新開發的專案,估計沒人會用webform技術。但是有些舊版 ......

    uj5u.com 2020-09-09 22:08:50 more
  • iis添加asp.net網站,訪問提示:由于擴展配置問題而無法提供您請求的

    今天在iis服務器配置asp.net網站,遇到一個問題,記錄一下: 問題:由于擴展配置問題而無法提供您請求的頁面。如果該頁面是腳本,請添加處理程式。如果應下載檔案,請添加 MIME 映射。 WindowServer2012服務器,添加角色安裝完.netframework和iis之后,運行aspx頁面 ......

    uj5u.com 2020-09-09 22:10:00 more
  • WebAPI-處理架構

    帶著問題去思考,大家好! 問題1:HTTP請求和回傳相應的HTTP回應資訊之間發生了什么? 1:首先是最底層,托管層,位于WebAPI和底層HTTP堆疊之間 2:其次是 訊息處理程式管道層,這里比如日志和快取。OWIN的參考是將訊息處理程式管道的一些功能下移到堆疊下端的OWIN中間件了。 3:控制器處理 ......

    uj5u.com 2020-09-09 22:11:13 more
  • 微信門戶開發框架-使用指導說明書

    微信門戶應用管理系統,采用基于 MVC + Bootstrap + Ajax + Enterprise Library的技術路線,界面層采用Boostrap + Metronic組合的前端框架,資料訪問層支持Oracle、SQLServer、MySQL、PostgreSQL等資料庫。框架以MVC5,... ......

    uj5u.com 2020-09-09 22:15:18 more
  • WebAPI-HTTP編程模型

    帶著問題去思考,大家好!它是什么?它包含什么?它能干什么? 訊息 HTTP編程模型的核心就是訊息抽象,表示為:HttPRequestMessage,HttpResponseMessage.用于客戶端和服務端之間交換請求和回應訊息。 HttpMethod類包含了一組靜態屬性: private stat ......

    uj5u.com 2020-09-09 22:15:23 more
  • 部署WebApi隨筆

    一、跨域 NuGet參考Microsoft.AspNet.WebApi.Cors WebApiConfig.cs中配置: // Web API 配置和服務 config.EnableCors(new EnableCorsAttribute("*", "*", "*")); 二、清除默認回傳XML格式 ......

    uj5u.com 2020-09-09 22:15:48 more
最新发布
  • C#多執行緒學習(二) 如何操縱一個執行緒

    <a href="https://www.cnblogs.com/x-zhi/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/2943582/20220801082530.png" alt="" /></...

    uj5u.com 2023-04-19 09:17:20 more
  • C#多執行緒學習(二) 如何操縱一個執行緒

    C#多執行緒學習(二) 如何操縱一個執行緒 執行緒學習第一篇:C#多執行緒學習(一) 多執行緒的相關概念 下面我們就動手來創建一個執行緒,使用Thread類創建執行緒時,只需提供執行緒入口即可。(執行緒入口使程式知道該讓這個執行緒干什么事) 在C#中,執行緒入口是通過ThreadStart代理(delegate)來提供的 ......

    uj5u.com 2023-04-19 09:16:49 more
  • 記一次 .NET某醫療器械清洗系統 卡死分析

    <a href="https://www.cnblogs.com/huangxincheng/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/214741/20200614104537.png" alt="" /&g...

    uj5u.com 2023-04-18 08:39:04 more
  • 記一次 .NET某醫療器械清洗系統 卡死分析

    一:背景 1. 講故事 前段時間協助訓練營里的一位朋友分析了一個程式卡死的問題,回過頭來看這個案例比較經典,這篇稍微整理一下供后來者少踩坑吧。 二:WinDbg 分析 1. 為什么會卡死 因為是表單程式,理所當然就是看主執行緒此時正在做什么? 可以用 ~0s ; k 看一下便知。 0:000> k # ......

    uj5u.com 2023-04-18 08:33:10 more
  • SignalR, No Connection with that ID,IIS

    <a href="https://www.cnblogs.com/smartstar/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/u36196.jpg" alt="" /></a>...

    uj5u.com 2023-03-30 17:21:52 more
  • 一次對pool的誤用導致的.net頻繁gc的診斷分析

    <a href="https://www.cnblogs.com/dotnet-diagnostic/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/3115652/20230225090434.png" alt=""...

    uj5u.com 2023-03-28 10:15:33 more
  • 一次對pool的誤用導致的.net頻繁gc的診斷分析

    <a href="https://www.cnblogs.com/dotnet-diagnostic/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/3115652/20230225090434.png" alt=""...

    uj5u.com 2023-03-28 10:13:31 more
  • C#遍歷指定檔案夾中所有檔案的3種方法

    <a href="https://www.cnblogs.com/xbhp/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/957602/20230310105611.png" alt="" /></a&...

    uj5u.com 2023-03-27 14:46:55 more
  • C#/VB.NET:如何將PDF轉為PDF/A

    <a href="https://www.cnblogs.com/Carina-baby/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/2859233/20220427162558.png" alt="" />...

    uj5u.com 2023-03-27 14:46:35 more
  • 武裝你的WEBAPI-OData聚合查詢

    <a href="https://www.cnblogs.com/podolski/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/616093/20140323000327.png" alt="" /><...

    uj5u.com 2023-03-27 14:46:16 more