Реализация интерфейсов C#

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

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

class имя_класса : имя_интерфейса {
   // тело класса
}

где имя_интерфейса — это конкретное имя реализуемого интерфейса. Если уж интерфейс реализуется в классе, то это должно быть сделано полностью. В частности, реализовать интерфейс выборочно и только по частям нельзя.
В классе допускается реализовать несколько интерфейсов. В этом случае все реализуемые в классе интерфейсы указываются списком через запятую. В классе можно наследовать базовый класс и в тоже время реализовать один или более интерфейс. В таком случае имя базового класса должно быть указано перед списком интерфейсов, разделяемых запятой.
Методы, реализующие интерфейс, должны быть объявлены как public. Дело в том, что в самом интерфейсе эти методы неявно подразумеваются как открытые, поэтому их реализация также должна быть открытой. Кроме того, возвращаемый тип и сигнатура реализуемого метода должны точно соответствовать возвращаемому типу и сигнатуре, указанным в определении интерфейса.
Ниже приведен пример программы, в которой реализуется представленный ранее интерфейс ISeries. В этой программе создается класс ByTwos, генерирующий последовательный ряд чисел, в котором каждое последующее число на два больше предыдущего.

// Реализовать интерфейс ISeries.
class ByTwos : ISeries {
   int start;
   int val;

   public ByTwos () {
      start = 0;
      val =0;
   }

   public int GetNext() {
      val += 2;
      return val;
   }.

   public void Reset() {
      val = start;
   }

   public void SetStart(int x) {
      start = x;
      val = start;
   }
}


Как видите, в классе ByTwos реализуются три метода, определяемых в интерфейсе ISeries. Как пояснялось выше, это приходится делать потому, что в классе нельзя реализовать интерфейс частично.
Ниже приведен код класса, в котором демонстрируется применение класса ByTwos, реализующего интерфейс ISeries.

// Продемонстрировать применение класса ByTwos,
// реализующего интерфейс.

using System;

class SeriesDemo {
   static void Main() {
      ByTwos ob = new ByTwos () ;

      for(int i=0; i < 5; i++)
         Console.WriteLine("Следующее число равно " + ob.GetNext());

      Console.WriteLine("\nСбросить");
      ob.Reset () ;
      for(int i=0; i < 5; i++)
      Console.WriteLine("Следующее число равно " + ob.GetNext());
      
      Console.WriteLine("\nНачать с числа 100");
      ob.SetStart(100);
      for(int i=0; i < 5; i++)
         Console.WriteLine("Следующее число равно " + ob.GetNext());
   }
}


Для того чтобы скомпилировать код класса SeriesDemo, необходимо включить в компиляцию файлы, содержащие интерфейс ISeries, а также классы ByTwos и SeriesDemo. Компилятор автоматически скомпилирует все три файла и сформирует из них окончательный исполняемый файл. Так, если эти файлы называются ISeries.cs, ByTwos.cs и SeriesDemo. cs, то программа будет скомпилирована в следующей командной строке:

>csc SeriesDemo.cs ISeries.cs ByTwos.cs

В интегрированной срёде разработки Visual Studio для этой цели достаточно ввести все три упомянутых выше файла в конкретный проект С#. Кроме того, все три компилируемых элемента (интерфейс и оба класса) допускается включать в единый файл.
Ниже приведен результат выполнения скомпилированного кода.
   Следующее число равно 2
   Следующее число равно 4
   Следующее число равно 6
   Следующее число равно 8
   Следующее число равно 10

   Сбросить.
   Следующее число равно 2
   Следующее число равно 4
   Следующее число равно 6
   Следующее число равно 8
   Следующее число равно 10
   
   Начать с числа 100.
   Следующее число равно 102
   Следующее число равно 104
   Следующее число равно 106
   Следующее число равно 108
   Следующее число равно 110

В классах, реализующих интерфейсы, разрешается и часто практикуется определять их собственные дополнительные члены. В качестве примера ниже приведен другой вариант класса ByTwos, в который добавлен метод GetPrevious (), возвращающий предыдущее значение.

// Реализовать интерфейс ISeries и добавить в
// класс ByTwos метод GetPrevious() .

class ByTwos : ISeries {
   int start;
   int val;
   int prev;

   public ByTwos() {
      start = 0;
      val = 0;
      prev = -2;
   }

   public int GetNext () {
      prev = val;    ,
      val += 2;
      return val;
   }

   public void Reset () {
      val = start;
      prev = start - 2;
   }

   public void SetStart(int x) {
      start = x;
      val = start;
      prev = val - 2;
   }

   // Метод, не указанный в интерфейсе ISeries.
   public int GetPrevious () {
      return prev;
   }
}

Как видите, для того чтобы добавить метод GetPrevious (), потребовалось внести изменения в реализацию методов, определяемых в интерфейсе ISeries. Но поскольку интерфейс для этих методов остается прежним, то такие изменения не вызывают никаких осложнений и не нарушают уже существующий код. В этом и заключается одно из преимуществ интерфейсов.
Как пояснялось выше, интерфейс может быть реализован в любом количестве классов. В качестве примера ниже приведен класс Primes, генерирующий ряд простых чисел. Обратите внимание на то, реализация интерфейса ISeries в этом классе коренным образом отличается от той, что предоставляется в классе ByTwos.

// Использовать интерфейс ISeries для реализации
// процесса генерирования простых чисел.

class Primes : ISeries {
   int start;
   int val;

   public Primes() {
      start = 2;
      val = 2;
   }

   public int GetNext () {
      int i, j;
      bool isprime;

      val++;
      for(i = val; i < 1000000; i++) {
         isprime = true;
     for (j = 2; j <= i / j; j++) {
        if ( (i % j ) == 0) {
           isprime = false;
              break;
            }
         }
         if(isprime) {
        val = i;
        break;
         }
      }
      return val;
   }

   public void Reset () {
      val = start;
   }

   public void SetStart(int x) {
      start = x;
      val = start;
   }
}


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