Книга: C# 4.0: полное руководство

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

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

При реализации члена интерфейса имеется возможность указать его имя полностью вместе с именем самого интерфейса. В этом случае получается явная реализация члена интерфейса, или просто явная реализация. Так, если объявлен интерфейс 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. Именно по этим ссылкам происходит обращение к объектам данного класса с целью вызвать методы соответствующих интерфейсов, благодаря чему и устраняется неоднозначность.

Оглавление книги


Генерация: 1.215. Запросов К БД/Cache: 3 / 0
поделиться
Вверх Вниз