C#中接口的顯式實(shí)現(xiàn)與隱式實(shí)現(xiàn)及其相關(guān)應(yīng)用案例詳解
C#中接口的顯式實(shí)現(xiàn)與隱式實(shí)現(xiàn)
最近在學(xué)習(xí)演化一款游戲項(xiàng)目框架時(shí)候,框架作者巧妙使用接口中方法的顯式實(shí)現(xiàn)來(lái)變相對(duì)接口中方法進(jìn)行“密封”,增加實(shí)現(xiàn)接口的類(lèi)訪(fǎng)問(wèn)方法的“成本”。
接口的顯式實(shí)現(xiàn)和隱式實(shí)現(xiàn):
先定義一個(gè)接口,接口中有這兩個(gè)方法。
public interface ICanSingSong
{
void SingJayChow();
void SingOther();
}接下來(lái)我們讓InterfaceDesignExample 繼承該接口。使用常用的隱式實(shí)現(xiàn)方法來(lái)實(shí)現(xiàn)SingJayChow方法,在Start函數(shù)中直接可以調(diào)用,而使用顯式實(shí)現(xiàn)的接口方法SingOther,則需要將類(lèi)的實(shí)力轉(zhuǎn)換為接口類(lèi)型才可以調(diào)用。
這樣相當(dāng)于告訴類(lèi),ICanSingSong.SingOther()樣式就是表明SIngOther是屬于ICanSingSong接口中的“私有方法”。調(diào)用時(shí)候先要將類(lèi)類(lèi)型轉(zhuǎn)換為接口。
public class InterfaceDesignExample : MonoBehaviour,ICanSingSong
{
void Start()
{
//接口的隱式實(shí)現(xiàn) 可以直接調(diào)用
SingJayChow();
//顯示調(diào)用則需要 準(zhǔn)換成接口 調(diào)用
//this.SingOther();
(this as ICanSingSong).SingOther();
}
/// <summary>
/// 接口的隱式實(shí)現(xiàn)
/// </summary>
public void SingJayChow()
{
Debug.Log("你說(shuō)家是唯一的城堡,隨著稻香一路奔跑~");
}
/// <summary>
/// 接口的顯式實(shí)現(xiàn)
/// </summary>
void ICanSingSong.SingOther()
{
Debug.Log("lalalalalalallalaal!");
}
}
我們這樣做的目的之一就是為了增加類(lèi)對(duì)接口中的一些方法的調(diào)用成本,和使用“private”修飾有類(lèi)似效果,降低對(duì)方法亂用的可能。
接口-抽象類(lèi)-子類(lèi) 使用顯式實(shí)現(xiàn)接口方法
同樣,我們先聲明一個(gè)接口:
//接口 Application
public interface IApplication
{
void Start();
void Update();
void Destroy();
void Test();
}抽象類(lèi)繼承該接口,并對(duì)生命周期函數(shù)進(jìn)行顯式實(shí)現(xiàn),而供子類(lèi)繼承實(shí)現(xiàn)的方法為OnXXX
//抽象類(lèi)
public abstract class Application : IApplication
{
//不希望子類(lèi)去訪(fǎng)問(wèn)實(shí)現(xiàn)接口的方法
//使用顯式調(diào)用
void IApplication.Start()
{
OnStart();
}
void IApplication.Update()
{
OnUpdate();
}
void IApplication.Destroy()
{
OnDestroy();
}
public void Test()
{
Debug.Log("我是測(cè)試方法,隱式實(shí)現(xiàn)接口的方法,子類(lèi)可以輕松訪(fǎng)問(wèn)我");
}
//希望子類(lèi)的實(shí)現(xiàn)的方法
public abstract void OnStart();
public abstract void OnUpdate();
public abstract void OnDestroy();
}繼承抽象類(lèi)的子類(lèi)對(duì)生命周期函數(shù)進(jìn)行實(shí)現(xiàn):
//子類(lèi)
public class SubApplication : Application
{
public override void OnStart()
{
Test();
//Start(); 情況會(huì)發(fā)生遞歸調(diào)用 造成堆棧溢出 而此方法使用現(xiàn)實(shí)實(shí)現(xiàn) 所以在子類(lèi)中無(wú)法訪(fǎng)問(wèn) 避免情況發(fā)生
Debug.Log("OnStart");
}
public override void OnUpdate()
{
Debug.Log("OnUpdate");
}
public override void OnDestroy()
{
Debug.Log("OnDestroy");
}
}最后我們調(diào)用函數(shù):
//測(cè)試調(diào)用 //通過(guò)接口調(diào)用 顯示實(shí)現(xiàn)的方法 IApplication application = new SubApplication(); application.Start(); application.Update(); application.Destroy(); //通過(guò)類(lèi) 無(wú)法調(diào)用顯示實(shí)現(xiàn)的方法 只能訪(fǎng)問(wèn)使用OnXXXX方法 Application application2 = new SubApplication(); application2.OnStart(); application2.OnUpdate(); application2.OnDestroy();

這樣我們可以體會(huì)到接口作為高抽象層的存在,可以調(diào)用子類(lèi)具體實(shí)現(xiàn)的生命周期函數(shù),而子類(lèi)卻無(wú)法訪(fǎng)問(wèn)顯示實(shí)現(xiàn)的接口中“私有”的生命周期函數(shù)。
接口--子接口--靜態(tài)類(lèi)拓展 實(shí)現(xiàn)對(duì)接口函數(shù)的訪(fǎng)問(wèn)修飾
咳咳~故事開(kāi)始!
作為一個(gè)資深Jay迷,我同樣認(rèn)識(shí)一個(gè)自稱(chēng)曲庫(kù)的小精靈【SongLibrary】,它最拿手的三首歌曲是晴天、彩虹和說(shuō)好不哭.
//曲庫(kù)
public class SongLibrary
{
public void SingSunny()
{
Debug.Log("晴天:刮風(fēng)這天,我試著握你的手~");
}
//彩虹
public void SingRainbow()
{
Debug.Log("彩虹:你要離開(kāi),我知道很簡(jiǎn)單~");
}
public void SingNoCry()
{
Debug.Log("說(shuō)好不哭:說(shuō)好不哭讓我走~");
}
}這個(gè)小曲庫(kù)精靈居住在抽象出的留聲機(jī)中,我可以通過(guò)留聲機(jī)來(lái)和它交流播放對(duì)應(yīng)的歌曲。
public interface ISingAllSong
{
SongLibrary songLibrary { get; }
}留聲機(jī)上有三個(gè)按鈕,對(duì)應(yīng)播放歌曲,
播放晴天的按鈕功能:
抽象出子接口來(lái)繼承曲庫(kù)接口,通過(guò)靜態(tài)類(lèi)拓展來(lái)調(diào)用曲庫(kù)中對(duì)應(yīng)方法播放歌曲。
public interface ISingSunny : ISingAllSong
{
}
//靜態(tài)類(lèi)拓展
public static class SingSunnyExtensions
{
public static void SingSunny(this ISingSunny self)
{
self.songLibrary.SingSunny();
}
}同樣的方式,兩個(gè)子接口。兩個(gè)繼承子接口的靜態(tài)類(lèi)負(fù)責(zé)調(diào)用曲庫(kù)中的方法:
//彩虹
public interface ISingRainbow : ISingAllSong
{
}
//靜態(tài)類(lèi)拓展
public static class SingRainbowExtensions
{
public static void SingRainbow(this ISingRainbow self)
{
self.songLibrary.SingRainbow();
}
}
//說(shuō)好不哭
public interface ISingNoCry : ISingAllSong
{
}
//靜態(tài)類(lèi)拓展
public static class SingNoCryExtensions
{
public static void SingNoCry(this ISingNoCry self)
{
self.songLibrary.SingNoCry();
}
}這樣我們使用三個(gè)靜態(tài)類(lèi)來(lái)調(diào)用留聲機(jī)【interface】中居住的精靈【class】的方法,實(shí)現(xiàn)三個(gè)按鈕功能。
當(dāng)我想聽(tīng)歌時(shí)候,我只需要按照我的需求,搭配繼承對(duì)應(yīng)的子接口即可播放對(duì)應(yīng)的歌曲,不用怕我按下去的是晴天歌曲播放按鈕而短路到播放其它的歌曲曲目。
這樣保證,拿到對(duì)應(yīng)的子按鈕,只能播放對(duì)應(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();
//不能訪(fǎng)問(wèn)
//onlySingSunny.SingRainbow()
//onlySingSunny.SingNoCry();
var SingRainbowNoCry = new OnlySingRainbowNoCry();
SingRainbowNoCry.SingRainbow();
SingRainbowNoCry.SingNoCry();
//無(wú)法訪(fǎng)問(wèn)
//SingRainbowNoCry.SingSUnny();
}
}
總結(jié)一下:
使用顯示實(shí)現(xiàn)方式來(lái)對(duì)接口中方法進(jìn)行實(shí)現(xiàn),子類(lèi)是無(wú)法直接調(diào)用的,需要將類(lèi)轉(zhuǎn)換為接口類(lèi)型才可以調(diào)用。
同時(shí)如果接口中的方法不想讓子類(lèi)直接調(diào)用,可以讓抽象類(lèi)繼承接口原生方法,在抽象類(lèi)中進(jìn)行方法聲明供子類(lèi)調(diào)用,避免子類(lèi)對(duì)抽象層的直接交互。同時(shí),使用靜態(tài)類(lèi)拓展來(lái)限制子接口對(duì)父接口中存在函數(shù)方法的訪(fǎng)問(wèn),保證類(lèi)對(duì)所需方法的規(guī)范使用。
也就是說(shuō),盡可能不讓表層具象的類(lèi)輕松的訪(fǎng)問(wèn)到抽象層的其它不需要的功能,即類(lèi)需要什么就繼承對(duì)應(yīng)的子接口,實(shí)現(xiàn)對(duì)應(yīng)功能即可,多余的功能不要訪(fǎng)問(wèn)。
當(dāng)然也建議閱讀一下官方社區(qū)對(duì)顯式接口的實(shí)現(xiàn)的解釋說(shuō)明。
參考文章:
顯式接口實(shí)現(xiàn) - C# | Microsoft Learn
到此這篇關(guān)于C#中接口的顯式實(shí)現(xiàn)與隱式實(shí)現(xiàn)及其相關(guān)應(yīng)用案例的文章就介紹到這了,更多相關(guān)C#中接口的顯式實(shí)現(xiàn)與隱式實(shí)現(xiàn)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C#實(shí)現(xiàn)在兩個(gè)數(shù)字之間生成隨機(jī)數(shù)的方法
這篇文章主要介紹了C#實(shí)現(xiàn)在兩個(gè)數(shù)字之間生成隨機(jī)數(shù)的方法,在一些特殊場(chǎng)景會(huì)用到哦,需要的朋友可以參考下2014-08-08
C#將DataGridView中的數(shù)據(jù)保存到CSV和Excel中
這篇文章介紹了C#將DataGridView中的數(shù)據(jù)保存到CSV和Excel中的方法,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-04-04
C#創(chuàng)建及訪(fǎng)問(wèn)網(wǎng)絡(luò)硬盤(pán)的實(shí)現(xiàn)
本文主要介紹了C#創(chuàng)建及訪(fǎng)問(wèn)網(wǎng)絡(luò)硬盤(pán)的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-03-03
C#批量插入數(shù)據(jù)到Sqlserver中的三種方式
這篇文章主要為大家詳細(xì)介紹了C#批量插入數(shù)據(jù)到Sqlserver中的三種方式,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-12-12
C# 無(wú)邊框窗體邊框陰影效果的簡(jiǎn)單實(shí)現(xiàn)
這篇文章介紹了C# 無(wú)邊框窗體邊框陰影效果的簡(jiǎn)單實(shí)現(xiàn),有需要的朋友可以參考一下2013-10-10
C#連接藍(lán)牙設(shè)備的實(shí)現(xiàn)示例
本文主要介紹了C#連接藍(lán)牙設(shè)備的實(shí)現(xiàn)示例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-01-01

