Опубликован: 25.03.2010 | Доступ: свободный | Студентов: 1446 / 158 | Оценка: 4.31 / 4.00 | Длительность: 25:42:00
Лекция 10:

Интерфейсы, делегаты, события в C#

Диаграмма UML для приведенного кода, построенная в Visual Studio 2005, выглядит следующим образом


Приведем пример использования интерфейса, который наследует другой интерфейс (другие интерфейсы). Такие интерфейсы можно назвать многослойными. Для многослойных интерфейсов существует такое правило: если класс реализует интерфейс, который является производным цепочки других интерфейсов, то класс должен реализовать члены всех интерфейсов цепочки наследования. При этом сами наследуемые интерфейсы как типы должны иметь уровень доступности не ниже уровня доступности наследующего их класса. Но все члены, объявленные в наследуемых интерфейсах, всегда общедоступны в реализующем классе.

using System;
    
namespace Test
{
    interface A
    {
        void Method_A(); // Неявная доступность public
    
        // Method_A() - явно объявлен в A
    }
    
    // Одиночное наследование интерфейсов
    interface B : A
    {
        void Method_B(); // Неявная доступность public
     
        // Method_B() - явно объявлен в B
        // Method_A() - унаследован из A
   }
    
    interface C
    {
        void Method_C();
     
        // Method_C() - явно объявлен в C
   }
    
    // Множественное наследование интерфейсов
    interface D : B, C
    {
        void Method_D();
     
        // Method_D() - явно объявлен 
        // Method_C() - унаследован из C
        // Method_B() - унаследован из B 
        // Method_A() - унаследован из A через B
   }
    
    // Класс, который должен реализовать
    // все унаследованные интерфейсы
    class E : D
    {
        public void Method_A()
        {
            Console.WriteLine("Реализация Method_A()");
        }
    
        public void Method_B()
        {
            Console.WriteLine("Реализация Method_B()");
        }
    
        public void Method_C()
        {
            Console.WriteLine("Реализация Method_C()");
        }
    
        public void Method_D()
        {
            Console.WriteLine("Реализация Method_D()");
        }
    }
    
    // Вызывающий клиентский код
    class MyClass
    {
        public MyClass()
        {
            E ob = new E();
            ob.Method_A();
            ob.Method_B();
            ob.Method_C();
            ob.Method_D();
        }
    }
    
    // Запуск
    class Program
    {
        static void Main()
        {
            // Настройка консоли
            Console.Title = "Наследование интерфейсов";
            Console.ForegroundColor = ConsoleColor.White;
            Console.CursorVisible = false;
            Console.WindowWidth = 60;
            Console.WindowHeight = 10;
    
            new MyClass();// Чтобы сработал конструктор
    
            Console.ReadLine();
        }
    }
}
Листинг 10.2 . Наследование интерфейсов

Вот результат выполнения примера


Диаграмма UML для приведенного кода, построенная в Visual Studio 2005, выглядит следующим образом


Закрытая реализация членов интерфейса

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

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

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

using System;
    
namespace Test
{
    internal interface A // Доступен внутри текущей сборки
    {
        void Method_A(); // Неявная доступность public
    }
    
    // Одиночное наследование интерфейсов
    internal interface B : A // Доступен внутри текущей сборки
    {
        void Method_B(); // Неявная доступность public
    
        // Method_B() - явно объявлен в B
        // Method_A() - унаследован из A
    }
    
    // Изолированный интерфейс
    // Доступность по умолчанию internal
    interface C // Доступен внутри текущей сборки
    {
        void Method_C();
    
        // Method_C() - явно объявлен 
    }
    
    // Множественное наследование интерфейсов
    internal interface D : B, C // Доступен внутри текущей сборки
    {
        void Method_D();
    
        // Method_D() - явно объявлен 
        // Method_C() - унаследован из C
        // Method_B() - унаследован из B 
        // Method_A() - унаследован из B
    }
    
    // Класс, который должен реализовать
    // все унаследованные интерфейсы
    class E : D
    {
        void A.Method_A() // Здесь нельзя употреблять модификаторы доступа 
        {
        Console.WriteLine("Закрытая реализация Method_A()");
        }
        public void Method_A()// Функция доступа к закрытому члену
        {
        A a = this; // Неявное приведение типов (снижение полномочий ссылки)
        a.Method_A();
        }
    
        void B.Method_B() // Здесь нельзя употреблять модификаторы доступа
        {
        Console.WriteLine("Закрытая реализация Method_B()");
        }
        public void Method_B()// Функция доступа к закрытому члену
        {
        B b = this; // Неявное приведение типов (снижение полномочий ссылки)
        b.Method_B();
        }
    
        void C.Method_C() // Здесь нельзя употреблять модификаторы доступа
        {
        Console.WriteLine("Закрытая реализация Method_C()");
        }
        public void Method_C()// Функция доступа к закрытому члену
        {
        //C c = this;
        //c.Method_C();
        // Явное приведение типов (снижение полномочий ссылки)
        ((C)this).Method_C(); // Другой синтаксис
        }
    
        void D.Method_D() // Здесь нельзя употреблять модификаторы доступа
        {
        Console.WriteLine("Закрытая реализация Method_D()");
        }
        public void Method_D()// Функция доступа к закрытому члену
        {
        //D d = this;
        //d.Method_D();
        // Явное приведение типов (снижение полномочий ссылки)
        ((D)this).Method_D(); // Другой синтаксис
        }
    }
    
    // Вызывающий клиентский код
    class MyClass
    {
        public MyClass()
        {
        E ob = new E();
        // Вызываем закрытые члены реализации интерфейса 
        // через публичные функции доступа
        ob.Method_A();
        ob.Method_B();
        ob.Method_C();
        ob.Method_D();
        }
    }
    
    // Запуск
    class Program
    {
        static void Main()
        {
        // Настройка консоли
        Console.Title = "Закрытая реализация интерфейсов";
        Console.ForegroundColor = ConsoleColor.White;
        Console.CursorVisible = false;
        Console.WindowWidth = 60;
        Console.WindowHeight = 10;
    
        new MyClass();// Чтобы сработал конструктор
    
        Console.ReadLine();
        }
    }
}
Листинг 10.3 . Закрытая реализация членов интерфейса

Результат будет таким


Максим Филатов
Максим Филатов

Прошел курс. Получил код Dreamspark. Ввожу код на сайте, пишет:

Срок действия этого кода проверки уже истек. Проверьте, правильно ли введен код. У вас осталось две попытки. Вы также можете выбрать другой способ проверки или предоставить соответствующие документы, подтверждающие ваш академический статус.

 

Как активировать код?