Выбрать главу

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

public interface IProps

{

   void Prop1(string s);

   void Prop2 (string name, int val);

   void Ргор3 ();

}

public interface IPropsOne

{

   void Prop1(string s);

   void Prop2 (int val);

   void Ргор3 ();

}

У двух интерфейсов — по три метода с совпадающими именами, сигнатуры двух методов совпадают, а в одном случае различаются. Вот класс, наследующий оба интерфейса:

public class ClainTwo: IProps,IPropsOne

{

   /// <summary>

   /// склеивание методов двух интерфейсов

   /// </summary>

   /// <param name="s"></param>

   public void Prop1 (string s)

   {

       Console.WriteLine (s);

   }

   /// <summary>

   /// перегрузка методов двух интерфейсов

   /// </summary>

   /// <param name="s"></param>

   /// <param name="x"></param>

   public void Prop2(string s, int x)

   {

        Console.WriteLine(s +"; " + x);

   }

   public void Prop2 (int x)

   {

        Console.WriteLine(x);

   }

   /// <summary>

   /// переименование методов двух интерфейсов

   /// </summary> void IProps.Ргор3()

   {

         Console.WriteLine("Свойство 3 интерфейса 1");

   }

   void IPropsOne.Ргор3()

   {

         Console.WriteLine("Свойство 3 интерфейса 2");

   }

   public void Prop3FromInterface 1()

   {

        ((IProps)this). Ргор3();

   }

   public void Prop3FromInterface2()

   {

        ((IPropsOne)this). Ргор3();

   }

}

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

Приведу пример работы с объектами класса и интерфейсными объектами:

public void TestCliTwoInterfaces()

{

   Console.WriteLine("Объект ClainTwo вызывает методы двух интерфейсов!");

   Cli.ClainTwo claintwo = new Cli.ClainTwo ();

   claintwo.Prop1("Склейка свойства двух интерфейсов");

   claintwo.Ргор2("перегрузка::: ",99);

   claintwo.Prop2(9999);

   claintwo.Prop3FromInterface1 ();

   claintwo.Prop3FromInterface2 ();

   Console.WriteLine("Интерфейсный объект вызывает методы 1-го интерфейса!");

   Cli.IProps ip1 = (Cli.IProps)claintwo;

   ip1.Prop1("интерфейс IProps: свойство 1");

   ip2.Prop2("интерфейс 1", 88);

   ip1.Ргор3 ();

   Console.WriteLine("Интерфейсный объект вызывает методы 2-го интерфейса!");

   Cli.IPropsOne ip2 = (Cli.IPropsOne)claintwo;

   ip2.Propl("интерфейс IPropsOne: свойство1");

   ip2.Prop2 (7777);

   ip2.Ргор3 ();

}

Результаты работы тестирующей процедуры показаны на рис. 19.2.

Рис. 19.2. Решение проблемы коллизии имен Наследование от общего предка

Проблема наследования от общего предка характерна, в первую очередь, для множественного наследования классов. Если класс C является наследником классов A и B, а те, в свой черед, являются наследниками класса Parent, то класс наследует свойства и методы своего предка Parent дважды, один раз получая их от класса A, другой от — B. Это явление называется еще дублирующим наследованием. Для классов ситуация осложняется тем, что классы A и B могли по-разному переопределить методы родителя и для потомков предстоит сложный выбор реализации.