CS3L20——接口
本章代码关键字
接口
接口是行为的抽象规范,它也是一种自定义类型,关键字:inferface
继承接口和继承类的区别
继承类 是对象间的继承 包括特征行为等
继承接口 是行为间的继承 继承接口的行为规范 按照规范去实现内容
由于接口也是遵循 里氏替换原则,所以可以用接口容器装对象,
那么就可以实现装载 各种毫无关系但是却有相同行为 的对象
接口内部只能包含成员方法、索引器、属性、事件,且都不实现,都没有访问修饰符,
类可以继承多个接口,但只能继承一个类
接口可以继承接口 相当于在进行行为合并 带子类继承时再去实现具体的行为
接口可以被显式实现 主要用于实现不同接口中的同名函数的不同表现
实现接口的方法 可以加 virtual
关键字 在之后的子类里重写
需要执行某种行为,就以行为对应的接口类型作为参数,传入拥有这种行为的对象(继承了对应接口的类对象)
这样,执行行为就不需要指定具体的类型,以摆脱对具体实现的依赖
因此实际开发中,建议多多使用接口抽象行为,通过接口类型变量接收具体类对象 ,通过接口调用方法
接口只规定一个类有什么行为,而不关心行为如何实现,因此相比继承基类,接口更灵活也更加解耦合(不会耦合基类的实现)
例如,飞 这种行为可以单独抽象成接口,
这样 继承动物类的鸟类 和 继承机器类的飞机类 都可以继承该接口表明这两个类拥有这种行为,
这样就不需要把 飞 耦合到它们各自的基类内,毕竟不是所有的动物和机器都会飞
接口申明的规范:
不包含成员变量,只包含:方法、属性、索引器、事件,且成员不能被实现
成员可以不用写访问修饰符,不能是私有的
接口不能继承类,但可以继承另一个接口
接口的使用规范:
类可以继承多个接口
类继承接口后,必须实现接口中的所有成员
特点:
它与类的申明相似
接口是用来继承的
接口不能被实例化,但可以作为容器存储对象
C# 接口的更多特性可见:一期视频看透C#接口的全部特性及用法_哔哩哔哩_bilibili (注:Unity开发不能全部使用其中的介绍的特性)
关于接口和抽象类的区别,详见:CS3L27——抽象类和接口的区别
接口的声明
接口关键字:interface
,接口可以认为是抽象行为 的基类,接口命名规范 帕斯卡前面加 I
不包含成员变量,只包含方法、属性、索引器、事件 ,成员不能被实现
声明示例:
1 2 3 4 5 6 7 8 interface IFly { void Fly () ; string Name { set ; get ; } int this [int index] { get ; set ; } event Action doSomething; }
接口的使用
接口用来继承,它表明某个类拥有这个接口的行为,接口也遵循里氏替换原则
类可以继承一个类,n个接口,继承了接口后,必须实现其中的内容,且必须是 public
的
实现的接口函数,可以加 virtual
再在子类重写
Visual Studio 可以点击灯泡图标里的实现接口来自动实现接口内的所有内容
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 class Animal { }class Person : Animal , IFly { public virtual void Fly () { } public string Name { get => Name; set => Name = value ; } public int this [int index] { get => 0 ; set => this [index] = value ; } public event Action doSomething; } internal class Program { static void Main (string [] args ) { IFly f = new Person(); } }
接口可以继承接口
接口继承接口时,不需要实现,待类继承接口后 类自己去实现所有内容
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 interface IWalk { void Walk () ; } interface IMove :IFly , IWalk { void Move () ; } class Test : IMove { public int this [int index] { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } public string Name { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } public event Action doSomething; public void Fly () { throw new NotImplementedException(); } public void Move () { throw new NotImplementedException(); } public void Walk () { throw new NotImplementedException(); } } internal class Program { static void Main (string [] args ) { IMove im = new Test(); IFly If = new Test(); IWalk iw = new Test(); Player p = new Player(); ISuperAtk isa = new Player(); IAtk ia = new Player(); } }
显式实现接口
当一个类继承两个接口,但是接口中存在着同名方法时,直接只实现一次同名方法是可以运行的,但是这样无法区分两个接口的区别
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 interface IAtk { void Atk () ; } interface ISuperAtk { void Atk () ; } class Player : IAtk , ISuperAtk { public void Atk () { } } internal class Program { static void Main (string [] args ) { Player p = new Player(); p.Atk() } }
如果需要区分两个接口的行为,为不同的接口分别实现不同的方法,则需要显式实现接口
显式实现接口 就是用 接口名.行为名
去实现
注意:显式实现接口时 不能写访问修饰符,如果接口里有方法是用 protected
修饰的也要用显式实现接口
显式实现接口后,接口的显式实现方法不能被直接点出来调用了,改成父类装子类或者用 as
来使用
指的一提的是,即使显式实现了多个接口的同名方法,
还是可以再实现一个没有显式实现的方法,通过类对象本身的类型执行
但是要注意,这个方法和其他显式实现方法不构成重载! 因为它们本质上不是一个名字
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 interface IAtk { void Atk () ; } interface ISuperAtk { void Atk () ; } class Player : IAtk , ISuperAtk { void IAtk.Atk() { Console.WriteLine("显式实现IAtk的方法" ); } void ISuperAtk.Atk() { Console.WriteLine("显式实现ISuperAtk的方法" ); } public void Atk () { Console.WriteLine("不是显式实现的方法" ); } } internal class Program { static void Main (string [] args ) { Player p = new Player(); ISuperAtk isa = new Player(); IAtk ia = new Player(); p.Atk(); (p as IAtk).Atk(); (p as ISuperAtk).Atk(); isa.Atk(); ia.Atk(); } }
输出:
1 2 3 4 5 不是显式实现的方法 显式实现IAtk的方法 显式实现ISuperAtk的方法 显式实现ISuperAtk的方法 显式实现IAtk的方法