Наследование реализаций интерфейсов
Класс наследует все реализации интерфейсов, содержащиеся в его базовых классах.
Без явной повторной реализации интерфейса, в производном классе нельзя изменить сопоставление интерфейсов, унаследованных им из базовых классов. Например, в объявлениях
interface IControl
{
void Paint();
}
class Control: IControl
{
public void Paint() {...}
}
class TextBox: Control
{
new public void Paint() {...}
}
метод Paint класса TextBox скрывает метод Paint в классе Control, однако не меняет сопоставление Control.Paint с IControl.Paint, и вызовы метода Paint в экземплярах класса и экземплярах интерфейса приведет к следующим результатам:
Control c = new Control();
TextBox t = new TextBox();
IControl ic = c;
IControl it = t;
c.Paint(); // invokes Control.Paint();
t.Paint(); // invokes TextBox.Paint();
ic.Paint(); // invokes Control.Paint();
it.Paint(); // invokes Control.Paint();
Тем не менее, при сопоставлении метода интерфейса с виртуальным методом в классе можно переопределить этот виртуальный метод в производных классах и изменить реализацию интерфейса. Например, изменение записи приведенных выше объявлений на
interface IControl
{
void Paint();
}
class Control: IControl
{
public virtual void Paint() {...}
}
class TextBox: Control
{
public override void Paint() {...}
}
приведет к следующим результатам
Control c = new Control();
TextBox t = new TextBox();
IControl ic = c;
IControl it = t;
c.Paint(); // invokes Control.Paint();
t.Paint(); // invokes TextBox.Paint();
ic.Paint(); // invokes Control.Paint();
it.Paint(); // invokes TextBox.Paint();
Так как явные реализации метода интерфейса не могут быть объявлены виртуальными, переопределить явную реализацию члена интерфейса невозможно. Однако в явной реализации члена интерфейса можно вызвать другой метод, который может быть объявлен виртуальным, что позволяет переопределить его в производных классах. Пример
interface IControl
{
void Paint();
}
class Control: IControl
{
void IControl.Paint() { PaintControl(); }
protected virtual void PaintControl() {...}
}
class TextBox: Control
{
protected override void PaintControl() {...}
}
В этом примере в классах, являющихся производными класса Control, можно указать реализацию метода IControl.Paint путем переопределения метода PaintControl.
Повторная реализация интерфейса
В классе, который наследует реализацию интерфейса, разрешается повторно реализовать этот интерфейс путем включения его в список базовых классов.
Для повторной реализации интерфейса действуют такие же правила сопоставления интерфейсов, что и для первой реализации интерфейса. Таким образом, унаследованное сопоставление интерфейсов не влияет на сопоставление интерфейсов, установленное в повторной реализации этого интерфейса. Например, в объявлениях
interface IControl
{
void Paint();
}
class Control: IControl
{
void IControl.Paint() {...}
}
class MyControl: Control, IControl
{
public void Paint() {}
}
тот факт, что в классе Control метод IControl.Paint сопоставлен методу Control.IControl.Paint, не влияет на повторную реализацию в классе MyControl, где метод IControl.Paint сопоставлен методу MyControl.Paint.
В процедуре сопоставления повторно реализованных интерфейсов участвуют унаследованные объявления открытых членов и унаследованные явные объявления членов интерфейса. Пример
interface IMethods
{
void F();
void G();
void H();
void I();
}
class Base: IMethods
{
void IMethods.F() {}
void IMethods.G() {}
public void H() {}
public void I() {}
}
class Derived: Base, IMethods
{
public void F() {}
void IMethods.H() {}
}
В этом примере реализация интерфейса IMethods в классе Derived сопоставляет методы этого интерфейса методам Derived.F, Base.IMethods.G, Derived.IMethods.H и Base.I.
При реализации интерфейса в классе также неявно реализуются все базовые интерфейсы этого интерфейса. Аналогичным образом повторная реализация интерфейса неявно является повторной реализацией всех базовых интерфейсов этого интерфейса. Пример
interface IBase
{
void F();
}
interface IDerived: IBase
{
void G();
}
class C: IDerived
{
void IBase.F() {...}
void IDerived.G() {...}
}
class D: C, IDerived
{
public void F() {...}
public void G() {...}
}
Здесь в повторной реализации интерфейса IDerived также повторно реализуется интерфейс IBase, в результате чего метод IBase.F сопоставлен методу D.F.