Теперь рассмотрим родственную проблему. Что делать, если вам нужно гарантировать, что методы, определенные данным интерфейсом, будут доступны только с помощью интерфейсных ссылок, а не объектных? В настоящий момент члены, определенные интерфейсом IPointy, доступны как с помощью объектных ссылок, так и по ссылке на IPointy.

Ответ на оба вопроса дает явная реализация интерфейса. Используя этот подход, вы можете гарантировать, что пользователь объекта сможет получить доступ К методам, определенным данным интерфейсом, только с помощью правильной интерфейсной ссылки, не допуская при этом конфликта имен. Для примера рассмотрите следующий обновленный класс Line (предполагая, что вы соответствующим образом обновили Hexagon и Circle).

// Используя явную реализацию метода, можно указать

// другие реализации 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;

<p>Разрешение конфликтов имен</p>

Явная реализаций интерфейса может оказаться очень полезной тогда, когда реализуются несколько интерфейсов, содержащих идентичные члены, Предположим. например, что вы создали класс, реализующий следующие новые типы интерфейса.

// Три интерфейса, определяющие методы с одинаковыми именами.

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.

<p>Построение иерархии интерфейсов</p>
Перейти на страницу:

Похожие книги