2019-7-29-C#-在基类定义好方法让子类继承接口就能实现
| title | author | date | CreateTime | categories |
|---|---|---|---|---|
|
C# 在基类定义好方法让子类继承接口就能实现
|
lindexi
|
2019-07-29 09:57:49 +0800
|
2019-07-12 08:26:16 +0800
|
C#
|
在 C# 里面,接口的定义只需要类里面存在和接口声明相同的方法或属性就可以,而存在的方法或属性是在子类定义的还是基类里面定义的都无所谓。也就是在基类里面写好了方法,但不继承接口,等子类继承接口的时候就不需要子类实现方法。通过这样的方法可以在基类里面添加一些辅助方法,而这些方法默认不给子类开启,除非子类继承了接口
在基类定义的方法,如果在子类继承的接口里面声明的方法刚好和基类定义的相同,那么子类可以不需要再次定义。在基类可以判断当前自己的类型是否继承了接口
这个方法用在基类里面期望在特定的代码里面给子类暴露一些内部的方法,但是又不能让子类随意调用。或者预设了一些方法,这些方法存在性能或其他的问题,只有子类声明自己需要这个功能的时候才被调用
内部方法隐藏
在基类里面有一些内部的方法,默认不让子类使用的,但只有某些特殊的子类的情况才能被使用。同时这些内部方法还可能被外部的其他方法调用,不一定是子类
按照以上的约定就可以写出如下代码
public interface ILindexiDb
{
string GetPrivateString();
} public class BassClass
{
public string GetPrivateString()
{
if (!(this is ILindexiDb))
{
throw new NotSupportedException("这个方法除非是林德熙逗比才能使用,其他人不能使用");
} return "林德熙是逗比";
}
}
从代码可以看到,除非这个类继承了 ILindexiDb 不然 GetPrivateString 方法将会异常,因为我期望这个方法只有我才能调用
那么假如我有一个 Foo 的接口里面就需要使用到对应的方法,而默认业务想要返回的方法是基类定义的上面的方法
public interface IFoo
{
void GetString();
}
不明真相的小伙伴可能会如何写?
public class Foo : BassClass, IFoo
{
public void GetString()
{
Console.WriteLine(GetPrivateString());
}
}
上面代码是小伙伴会直接写出的代码,然而这段代码没有运行的时候就会炸,原因是在基类判断当前这个类没有继承林德熙是逗比这个接口
在我将基类放在一个程序集编译为dll之后,小伙伴没有方法直接看到源代码,他在调用 GetPrivateString 方法的时候抛出了方法没有支持异常,于是小伙伴会认为这个方法还没实现,她就不会想要去使用这个方法
而林德熙逗比将会写出下面代码用来访问内部的方法
public class Foo2 : BassClass, ILindexiDb, IFoo
{
public void GetString()
{
Console.WriteLine(GetPrivateString());
}
}
因为注入的都是 IFoo 接口,小伙伴都不知道实际实现的 Foo2 里面做了什么,如果不信,请在 VisualStudio 里面用上代码,然后调试一下。此时很难知道 Foo2 里面做了什么魔法让调用 GetPrivateString 方法不会异常,因为在调试的时候是很难知道当前这个类继承了哪些接口,而一般调试的时候都不会注意到某个类继承的接口会影响到具体调用的方法
我写了很多调试的方法,请看dotnet 代码调试方法
引用子类方法
按照这个约定,其实还可以让基类在满足一定条件的时候才能执行,这个条件需要子类定义。这个方法是上面说到的内部方法隐藏的升级,用起来将会更复杂
在基类里面判断当前类是否继承了某个接口,如果继承了,那么将会可以调用接口的方法。这个方法一般用在某个接口的声明要用到很多基类的信息才能实现,或某个接口本身不适合在外部的其他类继承,只能由子类继承
例如我定义了接口,用来判断林德熙是不是逗比的接口,而这个接口的方法实现需要依赖于基类的内容才能判断,但基类的内容是私有的,从业务上也不应该让外部方法知道
public interface ILindexiConverter
{
bool CheckLindexiIsDoubi();
}
以下是基类的定义
public class BassClass
{
protected string Name { get; } = "林德熙逗比"; public string GetPrivateString()
{
// 忽略代码
}
}
基类里面定义的 Name 属性是不能给外部类知道的,要不大家都知道我逗比,只有子类才能知道
此时基类需要依赖 ILindexiConverter 的判断才能决定是否需要做业务
public string GetPrivateString()
{
// 忽略代码 if (!lindexiConverter.CheckLindexiIsDoubi())
{
throw new NotSupportedException("这个方法除非是林德熙逗比才能使用,其他人不能使用");
} }
然而 ILindexiConverter 接口除非是子类,其他类是无法按照预期做到的,于是在基类里面可以这样写
if (this is ILindexiConverter lindexiConverter)
{
if (!lindexiConverter.CheckLindexiIsDoubi())
{
throw new NotSupportedException("这个方法除非是林德熙逗比才能使用,其他人不能使用");
}
}
判断当前这个类是否有继承 ILindexiConverter 接口,如果有就调用方法,按照这个方式写小伙伴就更加不能简单调用这个方法
而作为逗比我将会写出下面的代码,用于调用
public class Foo2 : BassClass, ILindexiDb, IFoo, ILindexiConverter
{
public void GetString()
{
Console.WriteLine(GetPrivateString());
} /// <inheritdoc />
public bool CheckLindexiIsDoubi()
{
return base.Name == "林德熙逗比";
}
}
我在 Foo2 里面的 CheckLindexiIsDoubi 用到基类的属性判断,同时基类因为子类继承了预期接口而能使用
这就是通过在基类里面定义好方法和定义好代码逻辑,只要子类继承接口才能实现
2019-7-29-C#-在基类定义好方法让子类继承接口就能实现的更多相关文章
- C# 在基类定义好方法让子类继承接口就能实现
在 C# 里面,接口的定义只需要类里面存在和接口声明相同的方法或属性就可以,而存在的方法或属性是在子类定义的还是基类里面定义的都无所谓.也就是在基类里面写好了方法,但不继承接口,等子类继承接口的时候就 ...
- Kendo UI - Class 基类定义
在 kendo 中,使用原型继承机制,Class 是 Kendo 中的基类,定义了函数 extend 用来派生其它类. function Class() {} Class.extend = funct ...
- C++//菱形继承 //俩个派生类继承同一个基类 //又有某个类同时继承俩个派生类 //成为 菱形继承 或者 钻石 继承//+解决
1 //菱形继承 2 //俩个派生类继承同一个基类 3 //又有某个类同时继承俩个派生类 4 //成为 菱形继承 或者 钻石 继承 5 6 #include <iostream> 7 #i ...
- 派生类地址比基类地址少4(子类与基类指针强行转换的时候,值居然会发生变化,不知道Delphi BCB是不是也这样) good
大家对虚表并不陌生,都知道每个含有虚函数的类对象都有1个虚指针,但是在现实使用中,却总是因为这而调试半天,才发现原来是虚指针惹的祸.我这几天在调试代码时候也中招了,我的问题是这样的,如下图,CTree ...
- .NET Framework中Object基类有哪些方法?
ToString(),虚方法,任何子类可重写自定义 GetType(),非虚,返回类型名 Equals(),虚方法,默认情况下判定两个引用是否指向同一实例.(ReferenceEquals()功能相同 ...
- C#中通过类来继承两个接口,父类实例化接口中的方法,子类继承父类,调用方法
实现了父类继承接口,父类实例化接口的方法,子类继承父类,子类调用父类的方法直接使用 代码如下: using System; using System.Collections.Generic; usin ...
- Java Swing类 例子代码:将子类继承JFrame 并且接口按键监听ActionLisetener (将内容直接添加到JFrame不创建Contaniner)
package rom; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Container; import ...
- 流畅python学习笔记:第十一章:抽象基类
__getitem__实现可迭代对象.要将一个对象变成一个可迭代的对象,通常都要实现__iter__.但是如果没有__iter__的话,实现了__getitem__也可以实现迭代.我们还是用第一章扑克 ...
- 流畅的python学习笔记:第十一章:抽象基类
__getitem__实现可迭代对象.要将一个对象变成一个可迭代的对象,通常都要实现__iter__.但是如果没有__iter__的话,实现了__getitem__也可以实现迭代.我们还是用第一章扑克 ...
随机推荐
- Java门面模式(或外观模式)
门面模式(或外观模式)隐藏系统的复杂性,并为客户端提供一个客户端可以访问系统的接口. 这种类型的设计模式属于结构模式,因为此模式为现有系统添加了一个接口以隐藏其复杂性.门面模式涉及一个类,它提供客户端 ...
- python读取文件报错:pandas.errors.ParserError: iterator should return strings, not bytes (did you open the file in text mode?)
python 读取csv文件报错问题 import csv with open('E:/Selenium2script/DDT模块/test.csv','rb') as f: readers = cs ...
- what have we learnt in day five
what is file? virtual unit offered by operation system steps to open file 1.find the file_path(file_ ...
- 47-Ubuntu-系统信息-2-df和du查看磁盘和目录空间占用
序号 命令 作用 01 df -h disk free 显示磁盘剩余空间;-h以人性化的方式显示文件大小 02 du -h [目录名] disk usage 显示目录下的文件大小 注:显示磁盘信息的时 ...
- Unity3D中画拉选框(绘制多选框)
问题分析: 需要根据鼠标事件,摁下鼠标开始绘制选择框,抬起鼠标结束绘制. 实现思路: 该需求是屏幕画线,Unity内置了GL类 封装了OpenGL,可以通过GL类来实现一些简单的画图操作,这里也是使 ...
- js drag drop 收藏夹拖拽移除的简单例子
代码 <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title& ...
- js实现各种复制功能
引用: <script src="https://clipboardjs.com//dist/clipboard.min.js"></script> 示例1 ...
- Keil5-建立第一个STM32工程
此致:特别感谢作者Lomo-chen所写的文章给我的帮助,我尝试做了一下,成功了,今天整理一下. 一.建立文件夹: 1.在桌面或其他盘建立一个文件夹,此处名称为Test,用来存放工程程序. 2.在Te ...
- linux inode节点数报警处理
1.问题描述 zabbix 收到一台服务器的Free inodes is less than 20% on volume / 报警 登陆服务器查看 产生原因:一般就是小文件比较多,占用大量的inode ...
- Dao层结合Service层处理异常
1. 接口存在异常不利于解耦. 2. 将编译时异常转化为运行时异常或其子类,通知上层,上层可以根据自身能力选择处理或向上抛出. 举例: 将UserDao中的SQLException转化为DaoExce ...