namespace InterfaceNameClash
{
// Вывести изображение на принтер.
public interface IDrawToPrinter
{
void Draw();
}
}
Обратите внимание, что в каждом интерфейсе определен метод по имени Draw()
Octagon, то компилятор разрешит следующее определение:using System;
namespace InterfaceNameClash
{
class Octagon : IDrawToForm, IDrawToMemory, IDrawToPrinter
{
public void Draw()
{
// Разделяемая логика вывода.
Console.WriteLine("Drawing the Octagon...");
}
}
}
Хотя компиляция такого кода пройдет гладко, здесь присутствует потенциальная проблема. Выражаясь просто, предоставление единственной реализации метода Draw()
Octagon. Например, представленный ниже код будет приводить к вызову того же самого метода Draw() независимо от того, какой интерфейс получен:using System;
using InterfaceNameClash;
Console.WriteLine("***** Fun with Interface Name Clashes *****\n");
// Все эти обращения приводят к вызову одного
// и того же метода Draw()!
Octagon oct = new Octagon();
// Сокращенная форма записи, если переменная типа
// интерфейса в дальнейшем использоваться не будет.
((IDrawToPrinter)oct).Draw();
// Также можно применять ключевое слово is.
if (oct is IDrawToMemory dtm)
{
dtm.Draw();
}
Console.ReadLine();
Очевидно, что код, требуемый для визуализации изображения в окне, значительно отличается от кода, который необходим для вывода изображения на сетевой принтер или в область памяти. При реализации нескольких интерфейсов, имеющих идентичные члены, разрешить подобный конфликт имен можно с применением синтаксиса
Octagon:class Octagon : IDrawToForm, IDrawToMemory, IDrawToPrinter
{
// Явно привязать реализации Draw() к конкретным интерфейсам.
void IDrawToForm.Draw()
{
Console.WriteLine("Drawing to form..."); // Вывод на форму
}
void IDrawToMemory.Draw()
{
Console.WriteLine("Drawing to memory..."); // Вывод в память
}
void IDrawToPrinter.Draw()
{
Console.WriteLine("Drawing to a printer..."); // Вывод на принтер
}
}
Как видите, при явной реализации члена интерфейса общий шаблон выглядит следующим образом:
Обратите внимание, что при использовании такого синтаксиса модификатор доступа не указывается: явно реализованные члены автоматически будут закрытыми. Например, такой синтаксис недопустим:
// Ошибка! Модификатор доступа не может быть указан!
public void IDrawToForm.Draw()
{
Console.WriteLine("Drawing to form...");
}
Поскольку явно реализованные члены всегда неявно закрыты, они перестают быть доступными на уровне объектов. Фактически, если вы примените к типу Octagon
Draw(). Как и следовало ожидать, для доступа к требуемой функциональности должно использоваться явное приведение. В предыдущих операторах верхнего уровня уже используется явное приведение, так что они работают с явными интерфейсами.Console.WriteLine("***** Fun with Interface Name Clashes *****\n");
Octagon oct = new Octagon();
// Теперь для доступа к членам Draw() должно
// использоваться приведение.
IDrawToForm itfForm = (IDrawToForm)oct;
itfForm.Draw();
// Сокращенная форма записи, если переменная типа