接口
定义
用于规定一种规则由大家遵守,可以理解为契约。
例如只有司机才能够驾驶,无照驾驶将被视为犯罪,这就是社会契约的表现。以此来解释,才是对面向接口编程及其精髓的把握。
interface IDrivers
{
public void Drive();
}
类想要有驾驶特性,就必须遵守这种契约,故自定义类必须实现IDrivers接口,才能拥有“合法”驾驶能力,故接口是一组行为规范。例如:
class CarDriver : IDrivers
{
public void Drive()
{
Console.WriteLine("Drivers with a driver's license can driver cars");
}
}
接口还意味着同样的方法对不同的对象表现不同的行为,例如:
class BusDrivers : IDrivers
{
public void Drive()
{
Console.WriteLine("Expersenced drivers can drive buses");
}
}
使司机具有驾驶公共汽车的能力,除了实现接口IDrivers,还需要提供不同的行为方式(具有经验)。
接口的本质
在面向对象世界中,接口是实现首相机制的重要手段,通过接口实现可以部分的弥补继承和多态的纵向关系上的不足。接口在抽象机制上,表现为基于接口的多态性:
Public static void Main()
{
IList<IDrivers> drivers = new List<IDrivers>();
drivers.Add(new CarDriver());
drivers.Add(new BusDrivers());
foreach (IDrivers driver in drivers)
{
driver.Drive();
}
}
.NET中接口
接口多继承,CLR支持接口多继承,即一个对象可以代表多个不同的身份。例如:
public readonly struct DateTime : IComparable, IComparable<DateTime>, IConvertible, IEquatable<DateTime>, IFormattable, IParsable<DateTime>, ISpanFormattable, ISpanParsable<DateTime>, ISerializable, IUtf8SpanFormattable
DateTime实例代表多个身份,不同的身份具有不同的行为。
接口的本质:可以看做一个定义了抽象方法的类,该类只提供了方法的定义,没有方法的实现,以功能由接口的实现类来完成。
在托管堆中CLR维护着一个接口虚表来完成方法分派。该表基于方法表内的接口图信息创建,主要保存了接口实现的索引记录。
例如:
class CarDriver : IDrivers
{
void IDrivers.Drive()
{
Console.WriteLine("Drivers with a driver's license can driver cars");
}
}
在CarDriver 第一次加载时,CLR检查到CarDriver 实现了IDrivers中的Drive方法,则会在接口虚表中创建一条记录信息,用于保存CarDriver 方法表中实现了Drive方法的引用地址,其他实现了IDrivers的类型都会在接口虚表中创建相应的记录。因此,接口的方法调用是基于接口虚表进行的。
简单举例几个典型的接口简要分析,有助于我们熟悉框架类库: