Явная реализация интерфейса
Единственный класс или структура может реализовать любое количество интерфейсов. Из-за этого всегда существует вероятность реализации интерфейсов с членами, имеющими идентичные имена, и, следовательно, возникает необходимость в устранении конфликтов на уровне имен. При реализации члена интерфейса имеется возможность указать его имя полностью вместе с именем самого интерфейса. В этом случае получается явная реализация члена интерфейса, или просто явная реализация.
Когда один интерфейс наследует другой, то в производном интерфейсе может быть объявлен член, скрывающий член с аналогичным именем в базовом интерфейсе. Такое сокрытие имен происходит в том случае, если член в производном интерфейсе объявляется таким же образом, как и в базовом интерфейсе. Но если не указать в объявлении члена производного интерфейса ключевое слово new, то компилятор выдаст соответствующее предупреждающее сообщение.
Для явной реализации интерфейсного метода могут быть две причины. Во-первых, когда интерфейсный метод реализуется с указанием его полного имени, то такой метод оказывается доступным не посредством объектов класса, реализующего данный интерфейс, а по интерфейсной ссылке. Следовательно, явная реализация позволяет реализовать интерфейсный метод таким образом, чтобы он не стал открытым членом класса, предоставляющего его реализацию. И во-вторых, в одном классе могут быть реализованы два интерфейса с методами, объявленными с одинаковыми именами и сигнатурами. Но неоднозначность в данном случае устраняется благодаря указанию в именах этих методов их соответствующих интерфейсов. Рассмотрим каждую из этих двух возможностей явной реализации на следующем примере:
using System; namespace ConsoleApplication1 { public interface IName { void WriteName(); } public interface INameFamily { // Объявляем в данном интерфейсе такой же метод void WriteName(); void WriteFamily(); } public interface IUserInfo : INameFamily { // Обязательно нужно указать ключевое слово new // чтобы не скрывались методы базового интерфейса new void WriteName(); void WriteUserInfo(); } // Класс, реализующий два интерфейса class UserInfo : IUserInfo,IName { string ShortName, Family, Name; public UserInfo(string Name, string Family, string ShortName) { this.Name = Name; this.Family = Family; this.ShortName = ShortName; } // Используем явную реализацию интерфейсов // для исключения неоднозначности void IName.WriteName() { Console.WriteLine("Короткое имя: " + ShortName); } void INameFamily.WriteFamily() { Console.WriteLine("Фамилия: " + Family); } void INameFamily.WriteName() { Console.WriteLine("Полное имя: " + Name); } void IUserInfo.WriteName() { } public void WriteUserInfo() { UserInfo obj = new UserInfo(Name, Family, ShortName); // Для использования закрытых методов необходимо // создать интерфейсную ссылку IName link1 = (IName)obj; link1.WriteName(); INameFamily link2 = (INameFamily)obj; link2.WriteName(); link2.WriteFamily(); IUserInfo link3 = (IUserInfo)obj; link3.WriteName(); } } class Program { static void Main() { UserInfo obj = new UserInfo(Name: "Alexandr", ShortName: "Alex", Family: "Erohin"); obj.WriteUserInfo(); Console.ReadLine(); } } }
Важно уяснить, что интерфейсы являются фундаментальным компонентом .NET Framework. Какого бы типа приложение не разрабатывалось (веб-приложение, приложение с настольным графическим интерфейсом, библиотека доступа к данными и т.п.), работа с интерфейсами будет обязательной частью этого процесса. Подводя итог всему изложенному, отметим, что интерфейсы могут приносить чрезвычайную пользу в следующих случаях:
-
При наличии единой иерархии, в которой только какой-то набор производных типов поддерживает общее поведение.
-
При необходимости моделировать общее поведение, которое должно встречаться в нескольких иерархиях, не имеющих общего родительского класса помимо System.Object.
Комментарии