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#-在基类定义好方法让子类继承接口就能实现的更多相关文章

  1. C# 在基类定义好方法让子类继承接口就能实现

    在 C# 里面,接口的定义只需要类里面存在和接口声明相同的方法或属性就可以,而存在的方法或属性是在子类定义的还是基类里面定义的都无所谓.也就是在基类里面写好了方法,但不继承接口,等子类继承接口的时候就 ...

  2. Kendo UI - Class 基类定义

    在 kendo 中,使用原型继承机制,Class 是 Kendo 中的基类,定义了函数 extend 用来派生其它类. function Class() {} Class.extend = funct ...

  3. C++//菱形继承 //俩个派生类继承同一个基类 //又有某个类同时继承俩个派生类 //成为 菱形继承 或者 钻石 继承//+解决

    1 //菱形继承 2 //俩个派生类继承同一个基类 3 //又有某个类同时继承俩个派生类 4 //成为 菱形继承 或者 钻石 继承 5 6 #include <iostream> 7 #i ...

  4. 派生类地址比基类地址少4(子类与基类指针强行转换的时候,值居然会发生变化,不知道Delphi BCB是不是也这样) good

    大家对虚表并不陌生,都知道每个含有虚函数的类对象都有1个虚指针,但是在现实使用中,却总是因为这而调试半天,才发现原来是虚指针惹的祸.我这几天在调试代码时候也中招了,我的问题是这样的,如下图,CTree ...

  5. .NET Framework中Object基类有哪些方法?

    ToString(),虚方法,任何子类可重写自定义 GetType(),非虚,返回类型名 Equals(),虚方法,默认情况下判定两个引用是否指向同一实例.(ReferenceEquals()功能相同 ...

  6. C#中通过类来继承两个接口,父类实例化接口中的方法,子类继承父类,调用方法

    实现了父类继承接口,父类实例化接口的方法,子类继承父类,子类调用父类的方法直接使用 代码如下: using System; using System.Collections.Generic; usin ...

  7. Java Swing类 例子代码:将子类继承JFrame 并且接口按键监听ActionLisetener (将内容直接添加到JFrame不创建Contaniner)

    package rom; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Container; import ...

  8. 流畅python学习笔记:第十一章:抽象基类

    __getitem__实现可迭代对象.要将一个对象变成一个可迭代的对象,通常都要实现__iter__.但是如果没有__iter__的话,实现了__getitem__也可以实现迭代.我们还是用第一章扑克 ...

  9. 流畅的python学习笔记:第十一章:抽象基类

    __getitem__实现可迭代对象.要将一个对象变成一个可迭代的对象,通常都要实现__iter__.但是如果没有__iter__的话,实现了__getitem__也可以实现迭代.我们还是用第一章扑克 ...

随机推荐

  1. Application.GetOpenFilename 使用说明

    Application.GetOpenFilename(FileFilter, FilterIndex, Title, ButtonText, MultiSelect) 语法: 名称         ...

  2. HDU 5119 Happy Matt Friends (背包DP + 滚动数组)

    题目链接:HDU 5119 Problem Description Matt has N friends. They are playing a game together. Each of Matt ...

  3. C# Windows服务相关

    代码及注释 ServiceController sc = new ServiceController("gupdatem"); sc.Stop();//停止服务 sc.Start( ...

  4. HTML5 Canvas知识点学习笔记

    版权声明:本文为博主原创文章,未经博主同意不得转载. https://blog.csdn.net/huangyibin628/article/details/30108165 canvas ① 主要作 ...

  5. 如果通过cookies和localStorage取值?

    1. getCook : 设定setCookie值 let setCookie = setCookie('wan',data,7); function setCookie(c_name,value,e ...

  6. Ansible-随笔-7

    扩展Ansible的插件系统. 有的时候,如果Ansible内置的插件无法满足需求时,我们可以自己编写新插件. 以下情况下可以考虑开发新插件: 1.除Paramiko.本机SSH.Local.Winr ...

  7. touchWX使用 echarts

    <button bindtap="init" wx:if="{{!isLoaded}}">加载图表</button> <butto ...

  8. 5.1中容器(Container)和门面(Facade)的实现

    tp5.1中引入了容器(Container)和门面(Facade)这两个新的类 官方文档已经给出了定义: 容器(Container)实现类的统一管理,确保对象实例的唯一性. 门面(Facade)为容器 ...

  9. Batch - 忽略FORFILES “no files found” error

    ref:https://stackoverflow.com/questions/16820681/suppress-forfiles-no-files-found-error Solution: Th ...

  10. Android Android Studio 如何导出 Jar 给 Unity 使用

    大致步骤如下: 1.创建新的 Android Studio 工程 2.为此 Android Studio 工程创建 Android Library 类库(也就是一个 Module)(后面就是用它生成 ...