抽象类与接口⚓︎
一、抽象类与密封类⚓︎
01 抽象类⚓︎
抽象类:通过abstract
关键字声明,是不完整的且必须在派生类中实现的类。
示例:
Note
- 抽象类不能实例化;
- 抽象类的用途是作为多个派生类的共享基类使用;
- 抽象类中可以定义抽象方法,也可以没有,更多的抽象方法参考二、抽象方法 一节;
- 抽象类中的所有抽象方法必须被派生类实现。
02 密封类⚓︎
密封类:通过sealed
关键字声明,密封类禁止派生,因此其不能作为基类,不能是抽象的。
示例:
Tip
由于密封类从不用作基类,所以有些运行时优化可以略微提高密封类成员的调用速度。
二、抽象方法与虚方法⚓︎
01 抽象方法⚓︎
抽象方法:通过abstract
关键字声明的方法是抽象的,它不包含任何实现。
示例:
由于抽象方法声明不提供任何实现,因此抽象方法的声明不包含大括号,且以分号结尾,抽象方法的实现由 override
方法完成。
Note
- 抽象方法是隐式的虚方法,因此可以用来重写继承的虚方法;
- 抽象方法必须定义在抽象类中,但是抽象类不一定包含抽象方法;
- 抽象方法声明中使用
static
或virtual
修饰符是错误的; - 抽象方法必须在派生类被全部实现。
02 虚方法⚓︎
虚方法:通过virtual
关键字声明的方法是虚拟的,它应该包含方法体,必要时被子类重写。
抽象方法的定义使子类面临这样的问题:必须重写所有抽象方法。但是,如果有一个需求是,父类中存在一个方法,它具有方法体,子类据自己的需要决定是否重写,而不是必须重写。这是抽象方法无法完成的,因此就引入了“虚方法”。
virtual
修饰符不能与 static
、abstract private
或 override
修饰符一起使用。
示例:
Tip
- 当抽象类从基类继承虚方法时,抽象类可以使用抽象方法重写该虚方法。通过这种方式,抽象类可强制派生类向虚拟方法提供新的方法实现;
sealed
和override
一起使用会抵消虚效果。
三、接口⚓︎
01 接口定义⚓︎
接口定义协定。实现该协定的任何 class 或 struct 必须提供接口中定义的成员的实现,接口可以为成员定义默认实现。
接口:通过interface
关键字声明接口,接口中可以包含方法、属性、索引器、事件的声明(没有任何实现的签名)。
示例:
接口中可以包含默认实现,它们是
- 常量
- 运算符
- 静态构造函数
- 嵌套类型
- 静态字段、方法、属性、索引和事件
- 使用显式接口实现语法的成员声明
- 显式访问修饰符(默认访问权限为 public)
只能通过接口实例访问默认成员。
02 接口继承⚓︎
一个接口可从一个或多个基接口继承。 当接口重写基接口中的方法实现时,必须使用显式接口实现语法。
一个类同时实现基类和接口时,基类必须是实现列表中的第一项。
class ImplementationClass : ISampleInterface
{
// Explicit interface member implementation:
void ISampleInterface.SampleMethod()
{
// Method implementation.
}
static void Main()
{
// Declare an interface instance.
ISampleInterface obj = new ImplementationClass();
// Call the member.
obj.SampleMethod();
}
}
03 显示接口实现⚓︎
如果一个类实现的两个接口包含签名相同的成员,则在该类上实现此成员会导致这两个接口将此成员用作其实现。
示例:
public interface IControl
{
void Paint();
}
public interface ISurface
{
void Paint();
}
public class SampleClass : IControl, ISurface
{
// Both ISurface.Paint and IControl.Paint call this method.
public void Paint()
{
Console.WriteLine("Paint method in SampleClass");
}
}
// 调用测试
SampleClass sample = new SampleClass();
IControl control = sample;
ISurface surface = sample;
// The following lines all call the same method.
sample.Paint();
control.Paint();
surface.Paint();
// Output:
// Paint method in SampleClass
// Paint method in SampleClass
// Paint method in SampleClass
如果要单独定义实现,需要使用到显示接口实现,即在实现方法时,指定其所属的接口,例如:
public class SampleClass : IControl, ISurface
{
void IControl.Paint()
{
System.Console.WriteLine("IControl.Paint");
}
void ISurface.Paint()
{
System.Console.WriteLine("ISurface.Paint");
}
}
// 调用测试
SampleClass sample = new SampleClass();
IControl control = sample;
ISurface surface = sample;
// The following lines all call the same method.
//sample.Paint(); // Compiler error.
control.Paint(); // Calls IControl.Paint on SampleClass.
surface.Paint(); // Calls ISurface.Paint on SampleClass.
// Output:
// IControl.Paint
// ISurface.Paint