340
Глава.13 .Интерфейсы
internal sealed class SimpleType : IDisposable {
public void Dispose() { Console.WriteLine("Dispose"); }
}
Тогда таблица методов типа содержит записи, в которых представлены:
все экземплярные методы, определенные в типе
Object
и неявно унаследованные
от этого базового класса;
все
интерфейсные методы, определенные в явно унаследованном интерфейсе
IDisposable
(в нашем примере в интерфейсе
IDisposable
определен только
один метод —
Dispose
);
новый метод,
Dispose
, появившийся в типе
SimpleType
.
Чтобы упростить жизнь программиста, компилятор C# считает,
что появив-
шийся в типе
SimpleType
метод
Dispose
является реализацией метода
Dispose
из
интерфейса
IDisposable
. Компилятор C# вправе сделать такое предположение,
потому что метод открытый, а сигнатуры интерфейсного метода и нового метода
совпадают. Значит, методы принимают и возвращают одинаковые типы. Кстати,
если бы
новый метод
Dispose
был помечен как виртуальный, компилятор C# все
равно сопоставил бы этот метод с одноименным интерфейсным методом.
Сопоставляя новый метод с интерфейсным методом, компилятор C# генерирует
метаданные, указывающие на то, что обе записи в таблице методов типа
SimpleType
должны ссылаться на одну реализацию. Чтобы вам стало понятнее, следующий код
демонстрирует вызов открытого метода
Dispose
класса, а также вызов реализации
класса для метода
Dispose
интерфейса
IDisposable
.
public sealed class Program {
public static void Main() {
SimpleType st = new SimpleType();
// Вызов реализации открытого метода Dispose
st.Dispose();
// Вызов реализации метода Dispose интерфейса IDisposable
IDisposable d = st;
d.Dispose();
}
}
В первом вызове выполняется
обращение к методу
Dispose
,
определенно-
му в типе
SimpleType
. Затем я определяю переменную
d
интерфейсного типа
IDisposable
. Я инициализирую переменную
d
ссылкой на объект
SimpleType
.
Теперь при вызове
d.Dispose()
выполняется обращение к методу
Dispose
интер-
фейса
IDisposable
. Так как C# требует, чтобы открытый метод
Dispose
тоже был
реализацией для метода
Dispose
интерфейса
IDisposable
, будет выполнен тот же
код, и в этом примере вы не заметите какой-либо разницы. На выходе получим
следующее:
341
Обобщенные.интерфейсы
Dispose
Dispose
Теперь мы перепишем
SimpleType
, чтобы можно было увидеть разницу:
internal sealed class SimpleType : IDisposable {
public void Dispose() { Console.WriteLine("public Dispose"); }
void IDisposable.Dispose() { Console.WriteLine("IDisposable Dispose"); }
}
Не вызывая метод
Main
, мы можем просто перекомпилировать и запустить за-
ново
программу, и на выходе получим следующее:
public Dispose
IDisposable Dispose
Если в C# перед именем метода указано имя интерфейса, в котором определен
этот метод (в нашем примере —
IDisposable.Dispose
), то вы создаете
явную реа-
лизацию интерфейсного метода
(Explicit Interface Method Implementation, EIMI).
Заметьте: при явной реализации интерфейсного метода в C#
нельзя указывать
уровень доступа (открытый или закрытый). Однако когда компилятор создает
метаданные для метода, он назначает ему закрытый уровень доступа (
private
),
что запрещает любому коду использовать экземпляр класса простым вызовом
интерфейсного метода. Единственный способ вызвать интерфейсный метод — об-
ратиться через переменную этого интерфейсного типа.
Обратите внимание на то, что EIMI-метод не может быть виртуальным,
а значит,
его нельзя переопределить. Это происходит потому, что EIMI-метод в действитель-
ности не является частью объектной модели типа; это всего лишь средство связы-
вания интерфейса (набора вариантов поведения, или методов) с типом. Если такой
подход кажется вам немного неуклюжим, значит, вы все поняли
правильно
. Далее
в этой главе я опишу некоторые действенные причины для использования EIMI.
Do'stlaringiz bilan baham: