Рейтинговые книги
Читем онлайн C# 4.0: полное руководство - Герберт Шилдт

Шрифт:

-
+

Интервал:

-
+

Закладка:

Сделать
1 ... 98 99 100 101 102 103 104 105 106 ... 294

}

// В этом классе должны быть реализованы

//все методы интерфейсов IA и IB.

class MyClass : IB {

  public void Meth1() {

    Console.WriteLine("Реализовать метод Meth1().");

  }

  public void Meth2() {

    Console.WriteLine("Реализовать метод Meth2().");

  }

  public void Meth3() {

    Console.WriteLine("Реализовать метод Meth3().");

  }

}

class IFExtend {

  static void Main() {

    MyClass ob = new MyClass();

    ob.Meth1();

    ob.Meth2();

    ob.Meth3();

  }

}

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

Сокрытие имен при наследовании интерфейсов 

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

Явные реализации

При реализации члена интерфейса имеется возможность указать его имя полностью вместе с именем самого интерфейса. В этом случае получается явная реализация члена интерфейса, или просто явная реализация. Так, если объявлен интерфейс IMyIF

interface IMyIF {

  int MyMeth(int x) ;

}

то следующая его реализация считается вполне допустимой:

class MyClass : IMyIF {

  int IMyIF.MyMeth(int x) {

    return x / 3;

  }

}

Как видите, при реализации члена MyMeth() интерфейса IMyIF указывается его полное имя, включающее в себя имя его интерфейса.

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

В приведенном ниже примере программы демонстрируется интерфейс IEven, в котором объявляются два метода: IsEven() и IsOdd(). В первом из них определяется четность числа, а во втором — его нечетность. Интерфейс IEven затем реализуется в классе MyClass. При этом метод IsOdd() реализуется явно.

// Реализовать член интерфейса явно,

using System;

interface IEven {

  bool IsOdd(int x);

  bool IsEven(int x);

}

class MyClass : IEven {

  // Явная реализация. Обратите внимание на то, что

  // этот член является закрытым по умолчанию,

  bool IEven.IsOdd(int x) {

    if((x%2) != 0) return true;

    else return false;

  }

  // Обычная реализация,

  public bool IsEven(int x) {

    IEven о = this; // Интерфейсная ссылка на вызывающий объект,

    return !о.IsOdd(x);

  }

}

class Demo {

  static void Main() {

    MyClass ob = new MyClass();

    bool result;

    result = ob.IsEven(4);

    if(result) Console.WriteLine("4 — четное число.");

    // result = ob.IsOdd(4); // Ошибка, член IsOdd интерфейса IEven недоступен

    // Но следующий код написан верно,

    //поскольку в нем сначала создается

    // интерфейсная ссылка типа IEven на объект класса MyClass, а затем по

    // этой ссылке вызывается метод IsOdd().

    IEven iRef = (IEven) ob;

    result = iRef.IsOdd(3);

    if(result) Console.WriteLine("3 — нечетное число.");

  }

}

В приведенном выше примере метод IsOdd() реализуется явно, а значит, он недоступен как открытый член класса MyClass. Напротив, он доступен только по интерфейсной ссылке. Именно поэтому он вызывается посредством переменной о ссылочного типа IEven в реализации метода IsEven().

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

// Воспользоваться явной реализацией

// для устранения неоднозначности

using System;

interface IMyIF_A {

  int Meth(int x) ;

}

interface IMyIF_B {

  int Meth(int x) ;

}

// Оба интерфейса реализуются в классе MyClass.

class MyClass : IMyIF_A, IMyIF_B {

  // Реализовать оба метода Meth() явно,

  int IMyIF_A.Meth(int x) {

    return x + x;

  }

  int IMyIF_B.Meth(int x) {

    return x * x;

  }

  // Вызывать метод Meth() по интерфейсной ссылке.

  public int MethA(int x){

    IMyIF_A a_ob;

    a_ob = this;

    return a_ob.Meth(x); // вызов интерфейсного метода IMyIF_A

  }

  public int MethB(int x){

    IMyIF_B b_ob;

    b_ob = this;

    return b_ob.Meth(x); // вызов интерфейсного метода IMyIF_B

  }

}

class FQIFNames {

  static void Main() {

    MyClass ob = new MyClass();

    Console.Write("Вызов метода IMyIF_A.Meth(): ");

    Console.WriteLine(ob.MethA(3));

    Console.Write("Вызов метода IMyIF_B.Meth(): ");

    Console.WriteLine(ob.MethB(3)) ;

  }

}

Вот к какому результату приводит выполнение этой программы.

Вызов метода IMyIF_A.Meth(): 6

Вызов метода IMyIF_B.Meth(): 9

Анализируя приведенный выше пример программы, обратим прежде всего внимание на одинаковую сигнатуру метода Meth() в обоих интерфейсах, IMyIF_A и IMyIF_B. Когда оба этих интерфейса реализуются в классе MyClass, для каждого из них в отдельности это делается явно, т.е. с указанием полного имени метода Meth(). А поскольку явно реализованный метод может вызываться только по интерфейсной

ссылке, то в классе MyClass создаются две такие ссылки: одна — для интерфейса IMyIF_A, а другая — для интерфейса IMyIF_B. Именно по этим ссылкам происходит обращение к объектам данного класса с целью вызвать методы соответствующих интерфейсов, благодаря чему и устраняется неоднозначность.

Выбор между интерфейсом и абстрактным классом

Одна из самых больших трудностей программирования на C# состоит в правильном выборе между интерфейсом и абстрактным классом в тех случаях, когда требуется описать функциональные возможности, но не реализацию. В подобных случаях рекомендуется придерживаться следующего общего правила: если какое-то понятие можно описать с точки зрения функционального назначения, не уточняя конкретные детали реализации, то следует использовать интерфейс. А если требуются некоторые детали реализации, то данное понятие следует представить абстрактным классом.

1 ... 98 99 100 101 102 103 104 105 106 ... 294
На этой странице вы можете бесплатно читать книгу C# 4.0: полное руководство - Герберт Шилдт бесплатно.
Похожие на C# 4.0: полное руководство - Герберт Шилдт книги

Оставить комментарий