# 接口学习 注意点:C#8.0对接口有较大改动,之前的教程不再适用。比如:接口可以有默认实现,可以有static静态对象。 ## 接口定义 + 微软:An interface is a reference type that defines a set of members. + 译文:接口是定义一组特定对象(属性、方法、索引器、委托与事件)的引用类型。从 C# 8.0(.NET Core 3.0及以上,但.net framework不支持)开始,接口可以为成员定义默认实现,也可以定义static方法,这些方法必须有一个实现。 + **组合式定义**:接口是包含一组非抽象类或结构必须实现的相关功能定义的引用类型;接口是一种编程契约和规范;也是C#实现多继承的机制;又是多态的一种常用实现方式。 ## 接口特点 1. 接口可以包含属性、方法、索引器、委托与事件等对象,但不能包含字段,也不能包含构造或析构函数(对象的创建与销毁,应该在实现类所关心的,接口只关心需要实现的功能约定) 1. 接口中的对象都是公开权限的,否则接口无意义:不能使用范围修饰符(public private internal protected) 1. 不能有 static abstract virtual override sealed 等违反接口意义的修饰符,C#8.0之后static被允许。 1. 接口只包含对象的定义,不能包含对象的实现,也不能直接实例化接口. C#8.0之后,可以有默认实现,可以直接调用接口静态方法。 1. 接口的实现类必须实现接口中的所有成员,除非实现类本身是抽象类(通过具体的可执行代码实现接口抽象成员的操作);接口实现子类中,可用new关键字隐藏父接口中的方法。 1. 接口可以多继承,可用来解决C#类的单继承问题 1. 接口名称一般都以“I”作为首字母,以与实现类区分 1. 接口声明也适用于 “分部类”与“分部方法” ## 接口的隐式实现与显式实现 + 接口 ``` csharp /// /// 接口 /// public interface IBase { void Print(); } ``` + 隐式实现 ``` csharp /// /// 隐式实现接口 /// public class Base : IBase { //必须有访问修饰符 //对象(方法)名,即是接口对象(方法)名 public void Print() { Console.WriteLine($"隐式实现接口方法"); } } ``` + 显式实现 ``` csharp /// /// 显式实现接口 /// public class Base : IBase { //不允许有访问修饰符 //对象(方法)名为”接口名.对象(方法)名" void IBase.Print() { Console.WriteLine("显式实现接口方法"); } } ``` + 语法区别 > 隐式实现必须加 *访问修饰符* 显式实现不能用任何*访问修饰符* ;隐式实现对象名是接口对象名,显式实现,对象名为*接口名.对象名* + 调用区别 > 隐式实现,可以由实现类或接口类调用;显式实现只能由接口类调用。 ``` csharp //隐式实现调用 class Program { static void Main(string[] args) { //接口类可以调用 IBase base = new Base(); base.Print(); //实现类可以调用 Base base2 = new Base(); base2.Print(); } } //显式实现调用 class Program { static void Main(string[] args) { //接口类可以调用 IBase base = new Base(); base.Print(); //实现类不能调用 Base base2 = new Base(); //语法错误,不可调用 base2.Print(); } } ``` 小结: 1. 通常情况下,使用隐式方式实现接口; 2. 需要区分不同接口或者有同名对象时,使用显式实现; 3. 业务需要时,使用显式实现 ## 接口继承 ## 子类重复实现父类接口 ```csharp /// /// 接口 /// public interface IBase { string GetA(); string GetB(); } /// /// 接口实现基类 /// public class Base : IBase { public string GetA() { return "基类 GetA方法"; } public string GetB() { return "基类 GetB方法"; } } /// /// 接口实现子类 /// public class ChildA:Base,IBase { public string GetB() { return "实现子类 GetB方法"; } } ``` ## 运行时多态与编译时多态