跳转至

抽象类与接口⚓︎

一、抽象类与密封类⚓︎

01 抽象类⚓︎

抽象类:通过abstract关键字声明,是不完整的且必须在派生类中实现的类。

示例:

抽象类示例
public abstract class A
{
    // Class members here.
}

Note

  1. 抽象类不能实例化;
  2. 抽象类的用途是作为多个派生类的共享基类使用;
  3. 抽象类中可以定义抽象方法,也可以没有,更多的抽象方法参考二、抽象方法 一节;
  4. 抽象类中的所有抽象方法必须被派生类实现。

02 密封类⚓︎

密封类:通过sealed关键字声明,密封类禁止派生,因此其不能作为基类,不能是抽象的。

示例:

密封类示例
public sealed class B
{
    // Class members here.
}

Tip

由于密封类从不用作基类,所以有些运行时优化可以略微提高密封类成员的调用速度。

二、抽象方法与虚方法⚓︎

01 抽象方法⚓︎

抽象方法:通过abstract关键字声明的方法是抽象的,它不包含任何实现。

示例:

抽象方法定义
public abstract void AbstractMethod();

由于抽象方法声明不提供任何实现,因此抽象方法的声明不包含大括号,且以分号结尾,抽象方法的实现由 override 方法完成。

Note

  1. 抽象方法是隐式的虚方法,因此可以用来重写继承的虚方法;
  2. 抽象方法必须定义在抽象类中,但是抽象类不一定包含抽象方法;
  3. 抽象方法声明中使用 static 或 virtual 修饰符是错误的;
  4. 抽象方法必须在派生类被全部实现。

02 虚方法⚓︎

虚方法:通过virtual关键字声明的方法是虚拟的,它应该包含方法体,必要时被子类重写。

抽象方法的定义使子类面临这样的问题:必须重写所有抽象方法。但是,如果有一个需求是,父类中存在一个方法,它具有方法体,子类据自己的需要决定是否重写,而不是必须重写。这是抽象方法无法完成的,因此就引入了“虚方法”。

virtual 修饰符不能与 staticabstract private 或 override 修饰符一起使用。

示例:

虚方法的定义
public virtual void VirtualMethod()
{

}

Tip

  1. 当抽象类从基类继承虚方法时,抽象类可以使用抽象方法重写该虚方法。通过这种方式,抽象类可强制派生类向虚拟方法提供新的方法实现;
  2. sealedoverride 一起使用会抵消虚效果。

三、接口⚓︎

01 接口定义⚓︎

接口定义协定。实现该协定的任何 class 或 struct 必须提供接口中定义的成员的实现,接口可以为成员定义默认实现。

接口:通过interface关键字声明接口,接口中可以包含方法、属性、索引器、事件的声明(没有任何实现的签名)。

示例:

接口的定义
interface ISampleInterface
{
    void SampleMethod();
}

接口中可以包含默认实现,它们是

  • 常量
  • 运算符
  • 静态构造函数
  • 嵌套类型
  • 静态字段、方法、属性、索引和事件
  • 使用显式接口实现语法的成员声明
  • 显式访问修饰符(默认访问权限为 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