📚 Hub Books: Онлайн-чтение книгРазная литератураИнтернет-журнал "Домашняя лаборатория", 2007 №9 - Журнал «Домашняя лаборатория»

Интернет-журнал "Домашняя лаборатория", 2007 №9 - Журнал «Домашняя лаборатория»

Шрифт:

-
+

Интервал:

-
+
1 ... 358 359 360 361 362 363 364 365 366 ... 415
Перейти на страницу:
<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 могли по-разному переопределить методы родителя и для потомков предстоит сложный выбор реализации.

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

Начнем наш пример с наследования интерфейсов:

public interface IParent

{

   void ParentMethod();

}

public interface ISonl: IParent {

   void SonlMethod();

}

public interface ISon2:IParent {

   void Son2Method();

}

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

public class Pars: ISon1, ISon2

{

    public void ParentMethod()

    {

       Console.WriteLine("Это метод родителя!");

    }

    public void Son1Method()

    {

       Console.WriteLine("Это метод старшего сына!");

    }

    public void Son2Method()

    {

        Console.WriteLine("Это метод младшего сына!");

    }

}//class Pars

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

public void TestlParsons ()

{

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

    Cli. Pars ct = new Cli.Pars();

    ct.ParentMethod();

    ct.Son1Method();

    ct.Son2Method();

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

    Cli.IParent ip = (IParent)ct;

    ip.ParentMethod();

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

    Cli.ISonl ipl = (ISon1)ct;

    ip1.ParentMethod ();

    ip1.SonlMethod();

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

    Cli.ISon2 ip2 = (ISon2)ct;

    ip2.ParentMethod ();

    ip2.Son2Method();

}

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

Рис. 19.3. Дублирующее наследование интерфейсов

Встроенные интерфейсы

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

Упорядоченность объектов и интерфейс IComparable

Часто, когда создается класс, желательно задать отношение порядка на его объектах. Такой класс следует объявить наследником интерфейса IComparable. Этот интерфейс имеет всего один метод CompareTo (object obj), возвращающий целочисленное значение, положительное, отрицательное или равное нулю, в зависимости от выполнения отношения "больше", "меньше" или "равно".

Как правило, в классе вначале определяют метод CompareTo, а после этого вводят перегруженные операции, чтобы выполнять сравнение объектов привычным образом с использованием знаков операций отношения.

Давайте введем отношение порядка на классе Person, рассмотренном в лекции 16, сделав этот класс наследником интерфейса IComparable. Реализуем в этом классе метод интерфейса CompareTo:

public class Person: IComparable

{

    public int CompareTo(object pers)

    {

         const string s = "Сравниваемый объект не принадлежит классу Person";

         Person р = pers as Person;

         if (!p.Equals(null))

         return (fam.CompareTo(p.fam));

         throw new ArgumentException (s);

    }

    // другие компоненты класса

}

Поскольку аргумент метода должен иметь универсальный тип object, то перед выполнением сравнения его нужно привести к типу Person. Это приведение использует операцию as, позволяющую проверить корректность выполнения

1 ... 358 359 360 361 362 363 364 365 366 ... 415
Перейти на страницу:

Комментарии

Обратите внимание, что комментарий должен быть не короче 20 символов. Покажите уважение к себе и другим пользователям!

Никто еще не прокомментировал. Хотите быть первым, кто выскажется?