Теперь рассмотрим родственную проблему. Что делать, если вам нужно гарантировать, что методы, определенные данным интерфейсом, будут доступны только с помощью интерфейсных ссылок, а не объектных? В настоящий момент члены, определенные интерфейсом IPointy, доступны как с помощью объектных ссылок, так и по ссылке на IPointy.
Ответ на оба вопроса дает
// Используя явную реализацию метода, можно указать
// другие реализации Draw .
public class Line: Shape, IDraw3D {
// Этот метод можно вызвать только ссылкой на интерфейс IDraw3D.
void IDraw3D.Draw { Console.WriteLine("Отображение ЗD-линии…"); }
// Это можно вызвать только на уровне объекта.
public override void Draw { Console.WriteLine("Отображение линии…"); }
…
}
Как видите, при явной реализации члена интерфейса общий шаблон выглядит так:
// Нет! Это недопустимо.
public class Line: Shape, IDraw3D {
public void IDraw3D.Draw { // ‹= Ошибка!
Console.WriteLine("Отображение 3D-линии…");
}
…
}
Главной причиной использования явной реализации метода интерфейса является необходимость "привязки" соответствующего метода интерфейса к уровню интерфейса. Если добавить ключевое слово public, то это будет означать, что данный метод является членом открытого сектора класса, и "привязка" будет отменена. Тогда вызывающая сторона сможет вызывать только метод Draw, определенный базовым классом Shape на объектном уровне.
// Здесь вызывается переопределенный метод Shape.Draw.
Line myLine = new Line;
myLine.Draw;
Чтобы вызвать метод Draw, определенный с помощью IDraw3D, мы должны явно получить интерфейсную ссылку, используя любой из ранее указанных подходов. Например:
// Это обеспечит вызов метода IDraw3D.Draw.
Line myLine = new Line;
IDraw3D i3d = (IDraw3D) myLine;
i3d.Draw;
Разрешение конфликтов имен
Явная реализаций интерфейса может оказаться очень полезной тогда, когда реализуются несколько интерфейсов, содержащих идентичные члены, Предположим. например, что вы создали класс, реализующий следующие новые типы интерфейса.
// Три интерфейса, определяющие методы с одинаковыми именами.
public interface IDraw {
void Draw;
}
public interface IDrawToPrinter {
void Draw;
}
Если вы захотите построить класс с именем SuperImage (суперизображение), поддерживающий базовую визуализацию (IDraw), 3D-визуализацию (IDraw3D), а также сервис печати (IDrawToPrinter), то единственным способом обеспечить уникальную реализацию для каждого метода будет использование явной реализации интерфейса.
// Не выводится из Shape, но вводит конфликт имен.
public class SuperImage: IDraw, IDrawToPrinter, IDraw3D {
void IDraw.Draw {/* Логика базовой визуализации. */}
void IDrawToPrinter.Draw {/* Логика печати. */}
void IDraw3D.Draw {/* Логика 3D-визуализации. */}
}
Исходный код. Проект CustomInterface размешен в подкаталоге, соответствующем главе 7.
Построение иерархии интерфейсов