Информационный сайт

 

Реклама
bulletinsite.net -> Книги на сайте -> Программисту -> Троелсен Э. -> "С# и платформа .NET. Библиотека программиста" -> 88

С# и платформа .NET. Библиотека программиста - Троелсен Э.

Троелсен Э. С# и платформа .NET. Библиотека программиста — СПб.: Питер, 2004. — 796 c.
ISBN 5-318-00750-3
Скачать (прямая ссылка): cplatforma2004.pdf
Предыдущая << 1 .. 82 83 84 85 86 87 < 88 > 89 90 91 92 93 94 .. 320 >> Следующая

// Вопросы...
pji>Vic class Line : Shape, IDraw30 // И базовый и интерфейс определяю* метод
DrawO
{
public override void DrawO
{
Console.WritelineC'Drawing a line..."):
}
]
Компилятор, как несложно убедиться, вовсе не против такого кода. Однако что произойдет, если мы обратимся к объекту класса Ll пе таким образом:
// Вызываем Line. DrawO Lire PiyLlne = new Lint і'); myLine. DrawO:
II Вызываем Line.DrawO еще раз. но уже по-другому Idraw3D itfDraw3d - (IDraw3D) myLine: itfDraw3d.DrawO:
Исходя из того что мы знаем о базовом классе Shape и интерфейсе Юг^ЗО, очень похоже на то, что наследуют сразу два абстрактных метода DrawO. Для обоих абстрактных методов класс Line предлагает единую конкретную реализацию DrawO, и это вполне допустимо. Как мы бы ни вызвали потом этот метод — через ссылку на объект класса или через ссылку на интерфейс, — все равно будет вызван тот же самый вариант метода.
Однако проблемы еще не кончились. Что, если нам захочется иметь два метода с одинаковыми именами — IDraw3D. Draw() для отображения объекта в трех измерениях и замещенный метод Shape.Drew') для обычного его представления на плоскости? Вопрос можно и немного переформулировать. Как сделать так, чтобы к методам интерфейса можно было обратиться только через ссылку на интерфейс
(но не через ссылку на объект)? В нашей ситуации к методу DrawO можно обратиться обоими способами.
Ответ на эти вопросы состоит в том, чтобы воспользоваться явной реализацией
интерфейса (explicit interface implementation). Этим мы решаем сразу обе пробле-
Программирование с использованием интерфейсов 205
мы — и устраняем потенциальный конфликт имен, и запрещаем обращаться к методам интерфейса иначе как через ссылку на интерфейс. В нашей ситуации явная реализация интерфейса может выглядеть следующим образом:
.'/ При помощи явной реализации методов интерфейса мы можем определить // разные варианты метода DrawO public class Line : Shape. IDraw3D {
И Этот метод можно будет вызвать только через ссылку на интерфейс IDraw3D void IDraw3D.0rawO
{
Console.WriteLine("Drawing a 3D line..."):
.)
Il Этот метод можно будет вызвать только через ссылку на объект класса Line
public override void DrawO
{
Console.UriteLine("Drawing a line..,"):
!
)
При использовании явной реализации интерфейса необходимо помнить о некоторых ее тонкостях. Во-первых, мы уже не сможем задать модификатор облас ги видимости для методов интерфейса:
// Стоп! Так нельзя.
public class Line : Shape. IDraw3D
{
public void lDraw3D.0raw()
{
Console.WriteLinet"Drawing a 3D 1 ine...");
}
Г .
Немного поразмыслив, можно понять, откуда взялся такой запрет. Как мы уже для чего используется явная реализация интерфей-
са — так это для привязки методов интерфейса только на его уровне (чтобы к этим методам можно было обратиться только через ссылку на интерфейс). Если же мы используем модификатор области видимости publ і с, то это будет значить, что мы перевели этот метод в группу открытых методов класса, а это путает нам все карты.
Во-вторых, использование явного объявления интерфейса — пожалуй, единственный способ уберечься от потенциальных конфликтов между именами методов разных интерфейсов. Например, предположим, что у вас имеется класс, который реализует все три указанных ниже интерфейса:
// Три интерфейса определяют методы с одинаковыми именами
public interface IDraw
{
void DrawO;
}
public interface IDraw3D
{
void DrawO;
}
206 Глава 4 • Интерфейсы и коллекции
public interface lurawToPrinter
{
void DrawO;
;
Если вы хотите создать геометрическую фигуру, поддерживающую все три метода — Draw() для вывода обычного плоского изображения, Draw() для трехмерного изображения и 0raw() для вывода изображения на принтер, единственный выход -
воспользоваться явной реализацией интерфейса:
// Конфликтов имен не будет!
public class Superlmage : IDraw, IDrawToPrinter. IDraw3D {
void IDraw.DrawO
{
Il Вывод обычного плоского изображения
void IDrawToPrinter.Grawu {
it Вывод на принтер
/
void тигаиЗО. DrawO {
// Поддержка объемного изобразим
}
}
Код приложения Shapes можно найти в подкаталоге Chapter 4.
Создание иерархий интерфейсов
Как мы помним, в С# два класса могут вступать между собой в отношения наследования, при которых один класс станет базовым, а другой — производным. Точно так же один интерфейс С# может наследовать другому. Как обычно, базовый интерфейс (интерфейс более высокого уровня в иерархии) определяет общее поведение, в то время как производный интерфейс — более конкретное и специфическое. Простая иерархия интерфейсов может выглядеть следующим образом:
// Базовый интерфейс interface IDraw
!
void DrawO:
interface IDraw2 : !Draw
{
void DrawToPrinterO:
}
interface !Draw? : IDraw3
і
void DrawToMetaFi IeO;
"I
Отношения между этими интерфейсами представлены на рис. 4.5.
Программирование с использованием интерфейсов 207
!Draw
IDraw2
IDraw3
Рис. 4.5. Простая иерархия интерфейсов
Если наш класс должен поддерживать поведение, определенное во всех трех интерфейсах, он должен производиться от интерфейса самого нижнего уровня (в нашем случае — IDraw3). Все методы, определенные в базовых интерфейсах, будут автоматически включены в производные интерфейсы. Например:
Предыдущая << 1 .. 82 83 84 85 86 87 < 88 > 89 90 91 92 93 94 .. 320 >> Следующая
Реклама
Авторские права © 2009 AdsNet. Все права защищены.
Rambler's Top100