C#中接口的显式实现与隐式实现及其相关应用案例
C#中接口的显式实现与隐式实现
最近在学习演化一款游戏项目框架时候,框架作者巧妙使用接口中方法的显式实现来变相对接口中方法进行“密封”,增加实现接口的类访问方法的“成本”。
接口的显式实现和隐式实现:
先定义一个接口,接口中有这两个方法。
public interface ICanSingSong
{
void SingJayChow();
void SingOther();
}
接下来我们让InterfaceDesignExample 继承该接口。使用常用的隐式实现方法来实现SingJayChow方法,在Start函数中直接可以调用,而使用显式实现的接口方法SingOther,则需要将类的实力转换为接口类型才可以调用。
这样相当于告诉类,ICanSingSong.SingOther()样式就是表明SIngOther是属于ICanSingSong接口中的“私有方法”。调用时候先要将类类型转换为接口。
public class InterfaceDesignExample : MonoBehaviour,ICanSingSong
{
void Start()
{
//接口的隐式实现 可以直接调用
SingJayChow();
//显示调用则需要 准换成接口 调用
//this.SingOther();
(this as ICanSingSong).SingOther();
}
/// <summary>
/// 接口的隐式实现
/// </summary>
public void SingJayChow()
{
Debug.Log("你说家是唯一的城堡,随着稻香一路奔跑~");
}
/// <summary>
/// 接口的显式实现
/// </summary>
void ICanSingSong.SingOther()
{
Debug.Log("lalalalalalallalaal!");
}
}

我们这样做的目的之一就是为了增加类对接口中的一些方法的调用成本,和使用“private”修饰有类似效果,降低对方法乱用的可能。
接口-抽象类-子类 使用显式实现接口方法
同样,我们先声明一个接口:
//接口 Application
public interface IApplication
{
void Start();
void Update();
void Destroy();
void Test();
}
抽象类继承该接口,并对生命周期函数进行显式实现,而供子类继承实现的方法为OnXXX
//抽象类
public abstract class Application : IApplication
{
//不希望子类去访问实现接口的方法
//使用显式调用
void IApplication.Start()
{
OnStart();
}
void IApplication.Update()
{
OnUpdate();
}
void IApplication.Destroy()
{
OnDestroy();
}
public void Test()
{
Debug.Log("我是测试方法,隐式实现接口的方法,子类可以轻松访问我");
}
//希望子类的实现的方法
public abstract void OnStart();
public abstract void OnUpdate();
public abstract void OnDestroy();
}
继承抽象类的子类对生命周期函数进行实现:
//子类
public class SubApplication : Application
{
public override void OnStart()
{
Test();
//Start(); 情况会发生递归调用 造成堆栈溢出 而此方法使用现实实现 所以在子类中无法访问 避免情况发生
Debug.Log("OnStart");
}
public override void OnUpdate()
{
Debug.Log("OnUpdate");
}
public override void OnDestroy()
{
Debug.Log("OnDestroy");
}
}
最后我们调用函数:
//测试调用
//通过接口调用 显示实现的方法
IApplication application = new SubApplication();
application.Start();
application.Update();
application.Destroy();
//通过类 无法调用显示实现的方法 只能访问使用OnXXXX方法
Application application2 = new SubApplication();
application2.OnStart();
application2.OnUpdate();
application2.OnDestroy();

这样我们可以体会到接口作为高抽象层的存在,可以调用子类具体实现的生命周期函数,而子类却无法访问显示实现的接口中“私有”的生命周期函数。
接口--子接口--静态类拓展 实现对接口函数的访问修饰
咳咳~故事开始!
作为一个资深Jay迷,我同样认识一个自称曲库的小精灵【SongLibrary】,它最拿手的三首歌曲是晴天、彩虹和说好不哭.
//曲库
public class SongLibrary
{
public void SingSunny()
{
Debug.Log("晴天:刮风这天,我试着握你的手~");
}
//彩虹
public void SingRainbow()
{
Debug.Log("彩虹:你要离开,我知道很简单~");
}
public void SingNoCry()
{
Debug.Log("说好不哭:说好不哭让我走~");
}
}
这个小曲库精灵居住在抽象出的留声机中,我可以通过留声机来和它交流播放对应的歌曲。
public interface ISingAllSong
{
SongLibrary songLibrary { get; }
}
留声机上有三个按钮,对应播放歌曲,
播放晴天的按钮功能:
抽象出子接口来继承曲库接口,通过静态类拓展来调用曲库中对应方法播放歌曲。
public interface ISingSunny : ISingAllSong
{
}
//静态类拓展
public static class SingSunnyExtensions
{
public static void SingSunny(this ISingSunny self)
{
self.songLibrary.SingSunny();
}
}
同样的方式,两个子接口。两个继承子接口的静态类负责调用曲库中的方法:
//彩虹
public interface ISingRainbow : ISingAllSong
{
}
//静态类拓展
public static class SingRainbowExtensions
{
public static void SingRainbow(this ISingRainbow self)
{
self.songLibrary.SingRainbow();
}
}
//说好不哭
public interface ISingNoCry : ISingAllSong
{
}
//静态类拓展
public static class SingNoCryExtensions
{
public static void SingNoCry(this ISingNoCry self)
{
self.songLibrary.SingNoCry();
}
}
这样我们使用三个静态类来调用留声机【interface】中居住的精灵【class】的方法,实现三个按钮功能。
当我想听歌时候,我只需要按照我的需求,搭配继承对应的子接口即可播放对应的歌曲,不用怕我按下去的是晴天歌曲播放按钮而短路到播放其它的歌曲曲目。
这样保证,拿到对应的子按钮,只能播放对应的歌曲,保证曲目播放的有序性。
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();
}
}

总结一下:
使用显示实现方式来对接口中方法进行实现,子类是无法直接调用的,需要将类转换为接口类型才可以调用。
同时如果接口中的方法不想让子类直接调用,可以让抽象类继承接口原生方法,在抽象类中进行方法声明供子类调用,避免子类对抽象层的直接交互。同时,使用静态类拓展来限制子接口对父接口中存在函数方法的访问,保证类对所需方法的规范使用。
也就是说,尽可能不让表层具象的类轻松的访问到抽象层的其它不需要的功能,即类需要什么就继承对应的子接口,实现对应功能即可,多余的功能不要访问。
当然也建议阅读一下官方社区对显式接口的实现的解释说明。
参考文章:
[显式接口实现 - C# | Microsoft Learn](
C#中接口的显式实现与隐式实现及其相关应用案例的更多相关文章
- selenium-webdriver中的显式等待与隐式等待
在selenium-webdriver中等待的方式简单可以概括为三种: 1 导入time包,调用time.sleep()的方法传入时间,这种方式也叫强制等待,固定死等一个时间 2 隐式等待,直接调用i ...
- C# Interface显式实现和隐式实现
c#中对接口的实现方式有两种:隐式实现和显式实现,之前一直没仔细看过,今天查了些资料,在这里整理一下. 隐式实现的例子 interface IChinese { string Speak(); } p ...
- Scala 中的隐式转换和隐式参数
隐式定义是指编译器为了修正类型错误而允许插入到程序中的定义. 举例: 正常情况下"120"/12显然会报错,因为 String 类并没有实现 / 这个方法,我们无法去决定 Stri ...
- C# 数据类型转换 显式转型、隐式转型、强制转型
C# 的类型转换有 显式转型 和 隐式转型 两种方式. 显式转型:有可能引发异常.精确度丢失及其他问题的转换方式.需要使用手段进行转换操作. 隐式转型:不会改变原有数据精确度.引发异常,不会发生任何问 ...
- (java)selenium webdriver学习---三种等待时间方法:显式等待,隐式等待,强制等待
selenium webdriver学习---三种等待时间方法:显式等待,隐式等待,强制等待 本例包括窗口最大化,刷新,切换到指定窗口,后退,前进,获取当前窗口url等操作: import java. ...
- Java并发之显式锁和隐式锁的区别
Java并发之显式锁和隐式锁的区别 在面试的过程中有可能会问到:在Java并发编程中,锁有两种实现:使用隐式锁和使用显示锁分别是什么?两者的区别是什么?所谓的显式锁和隐式锁的区别也就是说说Synchr ...
- Scala 深入浅出实战经典 第61讲:Scala中隐式参数与隐式转换的联合使用实战详解及其在Spark中的应用源码解析
王家林亲授<DT大数据梦工厂>大数据实战视频 Scala 深入浅出实战经典(1-87讲)完整视频.PPT.代码下载: 百度云盘:http://pan.baidu.com/s/1c0noOt ...
- 多态设计 zen of python poem 显式而非隐式 延迟赋值
总结 1.python支持延迟赋值,但是给调用者带来了困惑: 2.显式而非隐式,应当显式地指定要初始化的变量 class Card: def __init__(self, rank, suit): s ...
- 大数据技术之_16_Scala学习_06_面向对象编程-高级+隐式转换和隐式值
第八章 面向对象编程-高级8.1 静态属性和静态方法8.1.1 静态属性-提出问题8.1.2 基本介绍8.1.3 伴生对象的快速入门8.1.4 伴生对象的小结8.1.5 最佳实践-使用伴生对象解决小孩 ...
- Scala 学习之路(十三)—— 隐式转换和隐式参数
一.隐式转换 1.1 使用隐式转换 隐式转换指的是以implicit关键字声明带有单个参数的转换函数,它将值从一种类型转换为另一种类型,以便使用之前类型所没有的功能.示例如下: // 普通人 clas ...
随机推荐
- React 逃离闭包陷阱
众所周知,JavaScript 中的闭包(Closures)一定是这种语言最可怕的特性之一,即使是无所不知的 ChatGPT 也是这样说的.另外它可能也是最隐蔽的语言特性之一,我们在编写 React ...
- 力扣686(java)-重复叠加字符串匹配(中等)
题目: 给定两个字符串 a 和 b,寻找重复叠加字符串 a 的最小次数,使得字符串 b 成为叠加后的字符串 a 的子串,如果不存在则返回 -1. 注意:字符串 "abc" 重复叠加 ...
- HarmonyOS NEXT应用开发案例—自定义日历选择器
介绍 本示例介绍通过CustomDialogController类显示自定义日历选择器. 效果图预览 使用说明 加载完成后显示主界面,点当前日期后会弹出日历选择器,选择日期后会关闭弹窗,主页面日期会变 ...
- Flutter+FaaS一体化任务编排的思考与设计
作者:闲鱼技术-古风 Flutter+Serverless三端一体研发架构,客户端不仅仅是编写双端的代码,而是扩展了客户端的工作边界,形成完整的业务闭环.在新的研发模式落地与实践的过程中,一直在思考如 ...
- Arthas 使用的各类方式
简介: Arthas 是阿里巴巴开源的 Java 诊断工具.让我们能够在线排查项目发生的问题.除了知道它的存在之外,我们也需要知道我们如何去安装使用它,以便于提高我们日常开发解决 BUG 的效率. A ...
- 阿里云张献涛:自主最强DPU神龙的秘诀
简介:读懂云计算,才能看清DPU热潮. 微信公众号搜索"弹性计算百晓生",获取更多云计算知识. 如果细数最近火爆的科技概念,DPU必然位列其中. 这是英伟达一手捧红的新造富故事, ...
- 开源 Serverless 里程碑:Knative 1.0 来了
简介:近期Knative发布了1.0版本,达到了一个重要的里程碑.Knative自2018年7月首次发布以来, 版本不断的迭代发展,除了无数的错误修复.稳定性和性能增强之外,按时间顺序还进行了一些改 ...
- 系统架构面临的三大挑战,看 Kubernetes 监控如何解决?
简介: 随着 Kubernetes 的不断实践落地,我们经常会遇到负载均衡.集群调度.水平扩展等问题.归根到底,这些问题背后都暴露出流量分布不均的问题.那么,我们该如何发现资源使用,解决流量分布不均 ...
- Codeforces Round 927 (Div. 3) EFG
E:Link 题意:给定长度小于 \(4 \times 10^5\) 的整数 \(n\),求从 \(0\) 到 \(n\) 各数位变化次数之和. 如:\(n = 12345\) 个位变化 \(1234 ...
- 🔥httpsok-v1.8.1 一分钟搞定SSL证书自动续期
httpsok-v1.8.1 一分钟搞定SSL证书自动续期 简介 一行命令,一分钟轻松搞定SSL证书自动续期 httpsok 是一个便捷的 HTTPS 证书自动续签工具,专为 Nginx 服务器设计. ...