C#中接口的顯式實現(xiàn)與隱式實現(xiàn)及其相關(guān)應(yīng)用案例詳解
C#中接口的顯式實現(xiàn)與隱式實現(xiàn)
最近在學(xué)習(xí)演化一款游戲項目框架時候,框架作者巧妙使用接口中方法的顯式實現(xiàn)來變相對接口中方法進行“密封”,增加實現(xiàn)接口的類訪問方法的“成本”。
接口的顯式實現(xiàn)和隱式實現(xiàn):
先定義一個接口,接口中有這兩個方法。
public interface ICanSingSong { void SingJayChow(); void SingOther(); }
接下來我們讓InterfaceDesignExample 繼承該接口。使用常用的隱式實現(xiàn)方法來實現(xiàn)SingJayChow方法,在Start函數(shù)中直接可以調(diào)用,而使用顯式實現(xiàn)的接口方法SingOther,則需要將類的實力轉(zhuǎn)換為接口類型才可以調(diào)用。
這樣相當(dāng)于告訴類,ICanSingSong.SingOther()樣式就是表明SIngOther是屬于ICanSingSong接口中的“私有方法”。調(diào)用時候先要將類類型轉(zhuǎn)換為接口。
public class InterfaceDesignExample : MonoBehaviour,ICanSingSong { void Start() { //接口的隱式實現(xiàn) 可以直接調(diào)用 SingJayChow(); //顯示調(diào)用則需要 準換成接口 調(diào)用 //this.SingOther(); (this as ICanSingSong).SingOther(); } /// <summary> /// 接口的隱式實現(xiàn) /// </summary> public void SingJayChow() { Debug.Log("你說家是唯一的城堡,隨著稻香一路奔跑~"); } /// <summary> /// 接口的顯式實現(xiàn) /// </summary> void ICanSingSong.SingOther() { Debug.Log("lalalalalalallalaal!"); } }
我們這樣做的目的之一就是為了增加類對接口中的一些方法的調(diào)用成本,和使用“private”修飾有類似效果,降低對方法亂用的可能。
接口-抽象類-子類 使用顯式實現(xiàn)接口方法
同樣,我們先聲明一個接口:
//接口 Application public interface IApplication { void Start(); void Update(); void Destroy(); void Test(); }
抽象類繼承該接口,并對生命周期函數(shù)進行顯式實現(xiàn),而供子類繼承實現(xiàn)的方法為OnXXX
//抽象類 public abstract class Application : IApplication { //不希望子類去訪問實現(xiàn)接口的方法 //使用顯式調(diào)用 void IApplication.Start() { OnStart(); } void IApplication.Update() { OnUpdate(); } void IApplication.Destroy() { OnDestroy(); } public void Test() { Debug.Log("我是測試方法,隱式實現(xiàn)接口的方法,子類可以輕松訪問我"); } //希望子類的實現(xiàn)的方法 public abstract void OnStart(); public abstract void OnUpdate(); public abstract void OnDestroy(); }
繼承抽象類的子類對生命周期函數(shù)進行實現(xiàn):
//子類 public class SubApplication : Application { public override void OnStart() { Test(); //Start(); 情況會發(fā)生遞歸調(diào)用 造成堆棧溢出 而此方法使用現(xiàn)實實現(xiàn) 所以在子類中無法訪問 避免情況發(fā)生 Debug.Log("OnStart"); } public override void OnUpdate() { Debug.Log("OnUpdate"); } public override void OnDestroy() { Debug.Log("OnDestroy"); } }
最后我們調(diào)用函數(shù):
//測試調(diào)用 //通過接口調(diào)用 顯示實現(xiàn)的方法 IApplication application = new SubApplication(); application.Start(); application.Update(); application.Destroy(); //通過類 無法調(diào)用顯示實現(xiàn)的方法 只能訪問使用OnXXXX方法 Application application2 = new SubApplication(); application2.OnStart(); application2.OnUpdate(); application2.OnDestroy();
這樣我們可以體會到接口作為高抽象層的存在,可以調(diào)用子類具體實現(xiàn)的生命周期函數(shù),而子類卻無法訪問顯示實現(xiàn)的接口中“私有”的生命周期函數(shù)。
接口--子接口--靜態(tài)類拓展 實現(xiàn)對接口函數(shù)的訪問修飾
咳咳~故事開始!
作為一個資深Jay迷,我同樣認識一個自稱曲庫的小精靈【SongLibrary】,它最拿手的三首歌曲是晴天、彩虹和說好不哭.
//曲庫 public class SongLibrary { public void SingSunny() { Debug.Log("晴天:刮風(fēng)這天,我試著握你的手~"); } //彩虹 public void SingRainbow() { Debug.Log("彩虹:你要離開,我知道很簡單~"); } public void SingNoCry() { Debug.Log("說好不哭:說好不哭讓我走~"); } }
這個小曲庫精靈居住在抽象出的留聲機中,我可以通過留聲機來和它交流播放對應(yīng)的歌曲。
public interface ISingAllSong { SongLibrary songLibrary { get; } }
留聲機上有三個按鈕,對應(yīng)播放歌曲,
播放晴天的按鈕功能:
抽象出子接口來繼承曲庫接口,通過靜態(tài)類拓展來調(diào)用曲庫中對應(yīng)方法播放歌曲。
public interface ISingSunny : ISingAllSong { } //靜態(tài)類拓展 public static class SingSunnyExtensions { public static void SingSunny(this ISingSunny self) { self.songLibrary.SingSunny(); } }
同樣的方式,兩個子接口。兩個繼承子接口的靜態(tài)類負責(zé)調(diào)用曲庫中的方法:
//彩虹 public interface ISingRainbow : ISingAllSong { } //靜態(tài)類拓展 public static class SingRainbowExtensions { public static void SingRainbow(this ISingRainbow self) { self.songLibrary.SingRainbow(); } } //說好不哭 public interface ISingNoCry : ISingAllSong { } //靜態(tài)類拓展 public static class SingNoCryExtensions { public static void SingNoCry(this ISingNoCry self) { self.songLibrary.SingNoCry(); } }
這樣我們使用三個靜態(tài)類來調(diào)用留聲機【interface】中居住的精靈【class】的方法,實現(xiàn)三個按鈕功能。
當(dāng)我想聽歌時候,我只需要按照我的需求,搭配繼承對應(yīng)的子接口即可播放對應(yīng)的歌曲,不用怕我按下去的是晴天歌曲播放按鈕而短路到播放其它的歌曲曲目。
這樣保證,拿到對應(yīng)的子按鈕,只能播放對應(yīng)的歌曲,保證曲目播放的有序性。
public class InterfaceRuleExample : MonoBehaviour { public class OnlySingSunny : ISingSunny { SongLibrary ISingAllSong.songLibrary { get; } = new SongLibrary(); } public class OnlySingRainbowNoCry : ISingRainbow,ISingNoCry { SongLibrary ISingAllSong.songLibrary { get; } = new SongLibrary(); } void Start() { var onlySingSunny = new OnlySingSunny(); onlySingSunny.SingSunny(); //不能訪問 //onlySingSunny.SingRainbow() //onlySingSunny.SingNoCry(); var SingRainbowNoCry = new OnlySingRainbowNoCry(); SingRainbowNoCry.SingRainbow(); SingRainbowNoCry.SingNoCry(); //無法訪問 //SingRainbowNoCry.SingSUnny(); } }
總結(jié)一下:
使用顯示實現(xiàn)方式來對接口中方法進行實現(xiàn),子類是無法直接調(diào)用的,需要將類轉(zhuǎn)換為接口類型才可以調(diào)用。
同時如果接口中的方法不想讓子類直接調(diào)用,可以讓抽象類繼承接口原生方法,在抽象類中進行方法聲明供子類調(diào)用,避免子類對抽象層的直接交互。同時,使用靜態(tài)類拓展來限制子接口對父接口中存在函數(shù)方法的訪問,保證類對所需方法的規(guī)范使用。
也就是說,盡可能不讓表層具象的類輕松的訪問到抽象層的其它不需要的功能,即類需要什么就繼承對應(yīng)的子接口,實現(xiàn)對應(yīng)功能即可,多余的功能不要訪問。
當(dāng)然也建議閱讀一下官方社區(qū)對顯式接口的實現(xiàn)的解釋說明。
參考文章:
顯式接口實現(xiàn) - C# | Microsoft Learn
到此這篇關(guān)于C#中接口的顯式實現(xiàn)與隱式實現(xiàn)及其相關(guān)應(yīng)用案例的文章就介紹到這了,更多相關(guān)C#中接口的顯式實現(xiàn)與隱式實現(xiàn)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C#實現(xiàn)在兩個數(shù)字之間生成隨機數(shù)的方法
這篇文章主要介紹了C#實現(xiàn)在兩個數(shù)字之間生成隨機數(shù)的方法,在一些特殊場景會用到哦,需要的朋友可以參考下2014-08-08C#將DataGridView中的數(shù)據(jù)保存到CSV和Excel中
這篇文章介紹了C#將DataGridView中的數(shù)據(jù)保存到CSV和Excel中的方法,文中通過示例代碼介紹的非常詳細。對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2022-04-04C#創(chuàng)建及訪問網(wǎng)絡(luò)硬盤的實現(xiàn)
本文主要介紹了C#創(chuàng)建及訪問網(wǎng)絡(luò)硬盤的實現(xiàn),文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2022-03-03C#批量插入數(shù)據(jù)到Sqlserver中的三種方式
這篇文章主要為大家詳細介紹了C#批量插入數(shù)據(jù)到Sqlserver中的三種方式,具有一定的參考價值,感興趣的小伙伴們可以參考一下2016-12-12