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

Явные реализации C#, Реализации в C#, Интерфейс iMylF в C#, C# Полное руководство Герберт Шилдт, Язык программирования C#, C# полное руководство

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

interface IMylF {
   int MyMeth(int x);
}

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

class MyClass : IMylF {
   int IMylF.MyMeth(int x) {
      return x / 3;
   }
}

Как видите, при реализации члена MyMeth () интерфейса IMylF указывается его полное имя, включающее в себя имя его интерфейса.
Для явной реализации интерфейсного метода могут быть две причины. Во-первых, когда интерфейсный метод реализуется с указанием его полного имени, то такой метод оказывается доступным не посредством объектов класса, реализующего данный интерфейс, а по интерфейсной ссылке. Следовательно, явная реализация позволяет реализовать интерфейсный метод таким образом, чтобы он не стал открытым членом класса, предоставляющего его реализацию. И во-вторых, в одном классе могут быть реализованы два интерфейса с методами, объявленными с одинаковыми именами и сигнатурами. Но неоднозначность в данном случае устраняется благодаря указанию в именах этих методов их соответствующих интерфейсов. Рассмотрим каждую из этих двух возможностей явной реализации на конкретных примерах.
В приведенном ниже примере программы демонстрируется интерфейс 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(х);
   }
}

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 FOIFNames {
   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 (): б
   Вызов метода IMyIF_B.Meth (): 9

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