C#:接口(interface)

目錄

接口的核心是什么?

1. 什么是接口(Interface),為什么要用它?

2. 如何定義和使用接口?

3.什么是引用接口??

?如何“引用接口”?

“引用接口”的關鍵點

4. 接口與抽象類的區別

5. 接口的常見特性

6. 如何通過接口進行依賴注入?

7. 常見陷阱和注意事項

接口的核心是什么?

從最基本的角度看,人類總是需要一種方式來定義“規則”或“標準”,讓不同的人或事物按照相同的模式工作。比如,你去餐廳點餐,菜單上列出了各種菜品(規則),廚師和服務員必須按照菜單上的描述來準備和提供食物。接口在編程中就像這個菜單:它定義了一組方法和屬性,告訴類“如果你要實現我,你必須提供這些功能”。

在 C# 中,接口是一種抽象類型,用于定義行為規范(contract),但不提供實現。類或結構體可以通過實現接口來承諾遵守這些規范。接口的核心思想是:分離“做什么”(接口定義)和“怎么做”(類實現),從而提高代碼的靈活性、可擴展性和復用性。

1. 什么是接口(Interface),為什么要用它?

定義:接口是 C# 中的一種引用類型,用于聲明一組方法、屬性、事件或索引器的簽名,但不包含具體實現。接口本身不能被實例化,只能被類或結構體實現。

為什么要用接口而不是直接用類?

  • 從第一性原理看:如果你想讓多個類有相同的行為(比如都能“飛行”或“計算”),但它們的實現細節不同(比如鳥和飛機飛的方式不同),直接用類繼承會有局限,因為一個類只能繼承一個基類(單繼承)。接口解決了這個問題:它允許一個類實現多個接口,從而支持多重繼承的“行為”。

  • 接口的優勢:

    • 抽象和規范:接口定義了“應該做什么”,但不關心“怎么做”,讓開發者專注于實現。

    • 松耦合:通過接口編程(依賴抽象而非具體實現),代碼更靈活,易于替換或擴展。

    • 測試性:接口便于 mock(模擬)測試,可以用假實現替換真實實現。

    • 多功能性:一個類可以實現多個接口,擁有多種能力。

例子:假設你有一個系統,需要不同類型的運輸工具(車、船、飛機)都能“運輸”。你可以定義一個接口:

public interface ITransport
{void Move(); // 所有運輸工具必須實現這個方法
}

然后不同的類可以實現這個接口:?

public class Car : ITransport
{public void Move(){Console.WriteLine("車在路上行駛。");}
}public class Ship : ITransport
{public void Move(){Console.WriteLine("船在水上航行。");}
}

現在,你可以用同一個接口 ITransport 處理任何運輸工具,而不必關心具體類型。?

2. 如何定義和使用接口?

定義接口:

接口用 interface 關鍵字定義,里面只能包含方法、屬性、事件或索引器的簽名,不能有具體實現。接口成員默認是公有的(public)不能有訪問修飾符

例子:

public interface IShape
{double CalculateArea(); // 定義方法簽名string Name { get; set; } // 定義屬性簽名
}

實現接口:

類或結構體通過 : 接口名 來實現接口,并必須提供所有接口成員的具體實現。

例子:

public class Circle : IShape
{public string Name { get; set; }public double CalculateArea(){return Math.PI * Radius * Radius; // 假設有一個 Radius 字段}private double Radius { get; set; }public Circle(double radius){Radius = radius;Name = "圓";}
}public class Rectangle : IShape
{public string Name { get; set; }public double CalculateArea(){return Length * Width; // 假設有 Length 和 Width 字段}private double Length { get; set; }private double Width { get; set; }public Rectangle(double length, double width){Length = length;Width = width;Name = "矩形";}
}

使用接口:

你可以通過接口類型引用實現了該接口的任何對象,這被稱為“接口多態”。

例子:

IShape shape1 = new Circle(5); // 用接口引用 Circle 對象
IShape shape2 = new Rectangle(4, 6);Console.WriteLine($"{shape1.Name} 面積:{shape1.CalculateArea()}");
Console.WriteLine($"{shape2.Name} 面積:{shape2.CalculateArea()}");

輸出:?

圓 面積:78.53981633974483
矩形 面積:24

解釋:這里 IShape 是抽象的“合同”,Circle 和 Rectangle 都實現了這個合同。通過 IShape 接口,你可以統一處理不同形狀,而不必關心具體類型。?

3.什么是引用接口??

想象你在組織一場聚會,你希望邀請一些人來表演,比如歌手、魔術師和舞蹈家。你不關心他們具體是誰(比如張三還是李四),你只關心他們能做什么(唱歌、變魔術、跳舞)。所以,你會發出一份“邀請函”(接口),上面寫著:“只要你能唱歌,就來表演!”然后,任何符合條件的人(實現了這個接口的類)都可以來。

在 C# 中,“引用接口”就是說你用接口類型來指向(引用)實現了這個接口的某個對象。也就是說,你并不直接使用具體類的實例(如 Singer 或 Magician),而是通過接口(如 IPerformer)來操作它們。這讓你的代碼更靈活,因為你可以在運行時輕松替換不同的實現。

?如何“引用接口”?

還是用聚會的比喻:

  1. 定義規則(接口): 你先寫一份“邀請函”,說明表演者需要做什么

public interface IPerformer
{void Perform(); // 所有表演者必須能表演
}

這里,IPerformer 就像是“必須會唱歌或變魔術”的要求。?

????2.有人響應(類實現接口): 不同的人(類)根據邀請函的要求,承諾他們會表演 。

public class Singer : IPerformer
{public void Perform(){Console.WriteLine("我唱一首歌!");}
}public class Magician : IPerformer
{public void Perform(){Console.WriteLine("我變一個魔術!");}
}

這里,Singer 和 Magician 都說:“我能表演!”他們實現了 IPerformer 接口。?

3. 發邀請并引用(用接口類型引用對象): 你不直接請某個具體的人(比如只請 Singer),而是發出一張通用邀請,說“我要一個能表演的人”。然后,任何符合條件的人都可以來,你用“表演者”的身份(接口)來管理他們。

IPerformer performer = new Singer(); // 用接口引用 Singer 對象
performer.Perform(); // 輸出:我唱一首歌!performer = new Magician(); // 隨時換人,用接口引用 Magician 對象
performer.Perform(); // 輸出:我變一個魔術!

?解釋:這里 IPerformer 是一個“通用標簽”,你可以隨時用它指向 Singer 或 Magician。你只關心他們能“Perform”,而不關心具體是誰。

“引用接口”的關鍵點

  • 接口是抽象的:你不能直接創建接口的實例(比如 new IPerformer() 是錯誤的),因為接口只是規則,不是具體的東西。你只能用接口來引用實現了它的類。

  • 多態性:通過接口引用不同類的對象,這種能力叫多態(Polymorphism)。就像你請的表演者可以是歌手也可以是魔術師,但你用同一個方式(“表演”)來指揮他們。

  • 松耦合:如果你直接用類(比如只寫 Singer singer = new Singer();),代碼就和 Singer 緊緊綁在一起。如果以后想換成 Magician,你就得改代碼。但用接口(IPerformer performer = ...),你只需要換成新的實現,調用代碼不用變。

4. 接口與抽象類的區別

雖然接口和抽象類(abstract class)都有抽象行為,但它們有重要區別:

  • 接口:

    • 只包含簽名,沒有實現(C# 8.0 之后支持默認實現,但仍以簽名為主)。

    • 一個類可以實現多個接口。

    • 適合定義行為規范。

  • 抽象類:

    • 可以包含部分實現(抽象方法和普通方法)。

    • 一個類只能繼承一個抽象類。

    • 適合定義共享的基類邏輯和狀態。

選擇建議:如果只是定義“應該做什么”,用接口;如果需要共享代碼或狀態,用抽象類。

5. 接口的常見特性

  • 多個接口實現:一個類可以實現多個接口,用逗號分隔。

    例子:

public interface IFlyable
{void Fly();
}public interface ISwimable
{void Swim();
}public class Duck : IFlyable, ISwimable
{public void Fly(){Console.WriteLine("鴨子在飛!");}public void Swim(){Console.WriteLine("鴨子在游泳!");}
}

顯式接口實現:如果同一個接口方法在不同接口中有沖突,可以用顯式實現。

例子:

public interface I1
{void Method();
}public interface I2
{void Method();
}public class MyClass : I1, I2
{void I1.Method() // 顯式實現 I1 的 Method{Console.WriteLine("I1 的方法");}void I2.Method() // 顯式實現 I2 的 Method{Console.WriteLine("I2 的方法");}
}

?只有通過接口引用才能調用這些方法(比如 ((I1)myObject).Method())。

接口繼承:接口可以繼承其他接口。

例子:

public interface IBase
{void BaseMethod();
}public interface IDerived : IBase // IDerived 繼承 IBase
{void DerivedMethod();
}

6. 如何通過接口進行依賴注入?

接口是依賴注入(Dependency Injection, DI)的基礎。它的核心思想是:不直接依賴具體類,而是依賴接口,這樣可以輕松替換實現。

public interface ILogger
{void Log(string message);
}public class ConsoleLogger : ILogger
{public void Log(string message){Console.WriteLine($"日志:{message}");}
}public class MyService
{private readonly ILogger _logger;public MyService(ILogger logger) // 通過構造函數注入{_logger = logger;}public void DoSomething(){_logger.Log("服務正在運行...");}
}// 使用
ILogger logger = new ConsoleLogger();
MyService service = new MyService(logger);
service.DoSomething();

?好處:如果以后想換成文件日志(FileLogger),只需替換 logger,而無需改動 MyService。

7. 常見陷阱和注意事項

  • 接口不能包含字段:接口只能定義方法、屬性、事件,不能有字段或具體實現(除非使用默認接口方法,C# 8.0+)。

  • 空接口(Marker Interface):如果接口沒有任何成員,可能沒有太大意義,除非用于標記(比如 ISerializable)。

  • 命名約定:接口通常以 I 開頭(如 IList、IDisposable),以便與類區分。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/75543.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/75543.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/75543.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

基于卷積神經網絡CNN實現電力負荷多變量時序預測(PyTorch版)

前言 系列專欄:【深度學習:算法項目實戰】?? 涉及醫療健康、財經金融、商業零售、食品飲料、運動健身、交通運輸、環境科學、社交媒體以及文本和圖像處理等諸多領域,討論了各種復雜的深度神經網絡思想,如卷積神經網絡、循環神經網絡、生成對抗網絡、門控循環單元、長短期記…

關于inode,dentry結合軟鏈接及硬鏈接的實驗

一、背景 在之前的博客 缺頁異常導致的iowait打印出相關文件的絕對路徑-CSDN博客 里 2.2.3 一節里,我們講到了file,fd,inode,dentry,super_block這幾個概念,在這篇博客里,我們針對inode和dentr…

游戲引擎學習第201天

倉庫:https://gitee.com/mrxiao_com/2d_game_5 回顧之前的內容,并遇到了一次一階異常(First-Chance Exception)。 歡迎來到新一期的開發過程,我們目前正在編寫調試接口代碼。 當前,我們已經在布局系統上進行了一些工…

計算機視覺算法實戰——基于YOLOv8的行人流量統計系統

?個人主頁歡迎您的訪問 ?期待您的三連 ? ?個人主頁歡迎您的訪問 ?期待您的三連 ? ?個人主頁歡迎您的訪問 ?期待您的三連? ??? ????????? ?? 引言:智能客流分析的市場需求 在零售、交通、安防等領域,準確的行人流量統計對于商業決策、公共安全管理…

Redis是什么?架構是怎么樣的?

目錄 前言 一,Redis架構 1.1 本地緩存 1.2 遠程緩存 二,強大的Redis優點 2.1 支持多種數據類型 2.2 內存過期策略 2.3 內存淘汰策略 2.4 持久化 三,Redis是什么 前言 我是一個程序員,維護了一個商品服務,它的背后直連Mysql數據庫,假設商品服務對外每秒需要提供1萬次…

藍橋杯真題——傳送陣

原題連接:藍橋杯2024年第十五屆省賽真題-傳送陣 - C語言網 知識點:并查集 題目描述 小藍在環球旅行時來到了一座古代遺跡,里面并排放置了 n 個傳送陣,進入第 i 個傳送陣會被傳送到第 ai 個傳送陣前,并且可以隨時選擇…

彩虹表攻擊

1. 引言 密碼安全一直是信息安全領域的重要課題。攻擊者可以利用**暴力破解(Brute-Force Attack)和字典攻擊(Dictionary Attack)等方式嘗試破解密碼。然而,計算機性能的提升使得這些方法的效率不斷提高,其中彩虹表攻擊(Rainbow Table Attack)**是一種極具威脅性的密碼…

Vue2 監聽器 watcher

文章目錄 前言監聽器的作用:工作流程:基本用法1. 簡單監聽2. 對象形式配置 使用場景1. 執行異步操作2. 監聽路由變化3. 復雜對象/數組變化 關鍵配置項與計算屬性的區別動態添加監聽器注意事項 前言 提示:這里可以添加本文要記錄的大概內容&a…

Linux系統程序設計:從入門到高級Day02

這一篇 我帶大家復習一下,C語言中的文件 那一部分 大家注意 這里的圖并非原創 是當時我老師的圖片 本片作用主要是 后續會有文件相關操作,這篇幫大家復習C語言文件中的內容 有助于大家后面的理解。 文章中代碼大多是圖片格式,是因為這是我…

N元語言模型的時間和空間復雜度計算

對于N元語言模型,時間復雜度是O(V ^ {N-1}),空間復雜度是O(V ^ {N}),N是詞匯表的大小。 空間復雜度:存儲所有可能的N-1元組及其對應的詞的頻次需要大量的存儲空間。例如,對于一個三元模型(N3)&…

Tmux 核心操作速查指南

Tmux 最常用操作筆記 1. 基本概念 會話(Session):一個tmux會話可以包含多個窗口,適合長期任務管理。窗口(Window):每個窗口是一個獨立的終端界面,可包含多個面板。面板&#xff08…

哈希表系列一>兩數之和

目錄 題目:方法:暴力代碼:優化后代碼: 題目: 鏈接: link 方法: 暴力代碼: public int[] twoSum(int[] nums, int target) {解法一:暴力解法:int n nums.length;for(int…

端到端機器學習流水線(MLflow跟蹤實驗)

目錄 端到端機器學習流水線(MLflow跟蹤實驗)1. 引言2. 項目背景與意義2.1 端到端機器學習流水線的重要性2.2 MLflow的作用2.3 工業級數據處理需求3. 數據集生成與介紹3.1 數據集構成3.2 數據生成方法4. 機器學習流水線與MLflow跟蹤4.1 端到端機器學習流水線4.2 MLflow跟蹤實驗…

英語學習:讀科技論文的難處

如果讀起科技論文, 我們就知道自己到底欠缺什么知識了, 那是一個挨著一個的缺。 而且還沒有維基百科可用。 怎么辦?沒辦法!硬看! 而且還要面臨語言的差異性困難。比如這一句怎么翻譯比較合適?還是直接不翻譯…

001 使用單片機實現的邏輯分析儀——吸收篇

本內容記錄于韋東山老師的畢設級開源學習項目,含個人觀點,請理性閱讀。 個人筆記,沒有套路,一步到位,歡迎交流! 00單片機的邏輯分析儀與商業版FPGA的邏輯分析儀異同 對比維度自制STM32邏輯分析儀商業版邏…

基數排序算法解析與TypeScript實現

基數排序(Radix Sort)是一種高效的非比較型整數排序算法,通過逐位分配與收集的方式實現排序。本文將深入解析其工作原理,并給出完整的TypeScript實現。 一、算法原理 1. 核心思想 多關鍵字排序:將整數按位數切割成不同…

最新全開源碼支付系統,贈送3套模板

最新全開源碼支付系統,贈送3套模板 碼支付是專為個人站長打造的聚合免簽系統,擁有卓越的性能和豐富的功能。它采用全新輕量化的界面UI 讓您能更方便快捷地解決知識付費和運營贊助的難題,同時提供實時監控和管理功能,讓您隨時隨地…

PHP基礎二【變量/輸出/數據類型/常量/字符串/運算符】

PHP基礎二 1. PHP變量2. PHP輸出3. 數據類型3.1 字符串3.2 整型3.3 浮點型3.4 布爾型3.5 數組3.6 對象3.7 NULL3.8 資源類型3.9 類型比較 4. 常量5. 運算符 1. PHP變量 1. 我們來看一個實例&#xff1a; <?php$x 5;$y 6;$z $x $y;echo $z; // echo 是輸出&#xff0c;…

ue5 仿鬼泣5魂類游戲角色和敵人沒有碰撞

UE5系列文章目錄 文章目錄 UE5系列文章目錄前言一、問題原因二、設置碰撞2.讀入數據 總結 前言 ue5 仿鬼泣5魂類游戲角色和敵人沒有碰撞 一、問題原因 在UE5中&#xff0c;角色和敵人沒有碰撞可能是由多種原因導致的&#xff0c;以下是一些可能的原因及解決方法&#xff1a…

《AdaBoost:從弱分類器到強模型的進化之路》

目錄 1. AdaBoost 的核心思想 2. AdaBoost 的關鍵步驟 步驟 1&#xff1a;初始化樣本權重 步驟 2&#xff1a;迭代訓練弱分類器 步驟 3&#xff1a;組合弱分類器 3. 用例子詳解 AdaBoost 數據集&#xff1a; 迭代過程&#xff1a; 第1輪&#xff08;t1&#xff09;&am…