C#. Узагальнені інтерфейси

Узагальнені інтерфейси. Синтаксис оголошення. Реалізація узагальнених інтерфейсів у класах. Приклади

Перед вивченням даної теми рекомендується ознайомитись з наступною темою:


Зміст


Пошук на інших ресурсах:




1. Синтаксис оголошення узагальненого інтерфейсу

У мові C# допускається оголошувати узагальнені інтерфейси. При оголошенні узагальненого інтерфейсу сигнатура методів, що оголошені в інтерфейсі, може містити посилання на параметризовані типи. Перелік параметризованих типів (наприклад, T1, T2, …, TN) задається в заголовку оголошення інтерфейсу між символами <>.

Загальна форма оголошення узагальненого інтерфейсу наступна:

interface InterfaceName<T1, T2, ..., TN>
{
  // ...
}

тут

  • InterfaceName – ім’я інтерфейсу;
  • T1, T2, TN – імена типів, які виступають в якості параметрів інтерфейсу.

Клас, що реалізує інтерфейс InterfaceName<T1, T2, …, TN> повинен оголошуватись наступним чином:

class ClassName<T1, T2, ..., TN> : InterfaceName<T1, T2, ..., TN>
{
  // ...
}

тут

  • ClassName – ім’я класу, що реалізує інтерфейс InterfaceName.

У найбільш простішому випадку інтерфейс отримує деякий тип T. У цьому випадку загальна форма оголошення інтерфейсу та його реалізації в класі має вигляд

interface InterfaceName<T>
{
  // ...
}

class ClassName<T> : InterfaceName<T>
{
  // ...
}

 

2. Приклади реалізації узагальненого інтерфейсу для одиночного типу T
2.1. Реалізація основних операцій над числами: додавання, віднімання

У прикладі оголошується узагальнений інтерфейс, який отримує параметром тип T. В інтерфейсі реалізовані основні операції додавання та віднімання чисел.

using System;

namespace ConsoleApp19
{
  // Інтерфейс, що отримує параметр типу T
  interface Operations<T>
  {
    // Оголошення методів, які використовують тип T
    double Add(T var1, T var2);
    double Sub(T var1, T var2);
  }

  // Клас, що реалізує інтерфейс MyInterface<T1, T2>
  class MyClass<T> : Operations<T>
  {
    // Реалізація методу, що використовує тип T
    public double Add(T var1, T var2)
    {
      double res = Convert.ToDouble(var1) + Convert.ToDouble(var2);
      return res;
    }

    public double Sub(T var1, T var2)
    {
      double res = Convert.ToDouble(var1) + Convert.ToDouble(var2);
      return res;
    }
  }

  class Program
  {
    static void Main(string[] args)
    {
      // Демонстрація використання узагальненого інтерфейсу
      // 1. Для типу-заповнювача int
      MyClass<int> mc1 = new MyClass<int>();
      double res1 = mc1.Add(23, 48);
      Console.WriteLine("res1 = {0}", res1);

      // 2. Для типу-заповнювача float
      MyClass<float> mc2 = new MyClass<float>();
      double res2 = mc2.Sub(8.804f, 1.704f);
      Console.WriteLine("res2 = {0:f}", res2);

      Console.ReadKey();
    }
  }
}

Результат виконання програми

res1 = 71
res2 = 10.51

 

2.2. Реалізація методів обробки масиву даних

Оголосити узагальнений інтерфейс IItems<T>, що містить наступні методи обробки масиву даних типу T:

  • Count() – повертає кількість елементів у масиві;
  • GetValue() – отримати елемент за його індексом;
  • SetValue() – встановити новий елемент в заданому індексі;
  • AddValue() – додати елемент в кінець масиву;
  • Delete() – видалити елемент з заданої позиції.

Оголосити узагальнений клас ArrayItems<T>, який реалізує інтерфейс IItems<T>. Крім методів інтерфейсу у класі додатково реалізувати:

  • масив даних типу T[];
  • конструктор без параметрів;
  • конструктор з параметром, який отримує інший масив типу T[];
  • метод Print(), що виводить масив у зручній для перегляду формі.

Текст програми, що розв’язує дану задачу наступний:

using System;

namespace ConsoleApp19
{
  // Узагальнений інтерфейс для масиву елементів різних типів
  interface IItems<T>
  {
    // Кількість елементів у масиві
    int Count();

    // Отримати елемент за його індексом
    T GetValue(int index);

    // Встановити новий елемент в заданому індексі
    void SetValue(T value, int index);

    // Додати елемент в кінець масиву
    void AddValue(T value);

    // Видалити елемент з позиції index
    void Delete(int index);
  }

  // Клас, що реалізує інтерфейс IItems<T>
  class ArrayItems<T> : IItems<T>
  {
    // Внутрішній масив
    T[] items;

    // Конструктори
    public ArrayItems()
    {
      // Встановити значення за замовчуванням
      items = default(T[]);
    }

    public ArrayItems(T[] _items)
    {
      items = _items;
    }

    // Метод, що повертає кількість елементів у масиві
    public int Count()
    {
      return items.Length;
    }

    // Отримати елемент за його індексом
    public T GetValue(int index)
    {
      return items[index];
    }

    // Встановити нове значення за індексом
    public void SetValue(T value, int index)
    {
      // Перевірка, чи індекс в допустимих межах
      if ((index>=0)&&(index<items.Length))
        items[index] = value;
    }

    // Додати елемент в кінець масиву
    public void AddValue(T value)
    {
      // Запам'ятати посилання на старий масив
      T[] items2 = items;

      // Створити новий масив
      items = new T[items.Length + 1];

      // items2 => items
      for (int i = 0; i < items.Length - 1; i++)
        items[i] = items2[i];

      // Додати останній елемент
      items[items.Length - 1] = value;
    }

    // Видалити елемент з позиції index
    public void Delete(int index)
    {
      // Перевірка, чи коректний index
      if ((index < 0) || (index >= items.Length))
        return;

      // Створити новий масив з довжиною на 1 менше
      T[] items2 = new T[items.Length - 1];

      // Скопіювати елементи оминаючи позицію index
      for (int i = 0; i < index; i++)
        items2[i] = items[i];
      for (int i = index + 1; i < items.Length; i++)
        items2[i - 1] = items[i];

      // Перенаправити внутрішнє посилання
      items = items2;
    }

    // Вивід масиву на екран
    public void Print(string message)
    {
      Console.Write(message + "\t\t");
      for (int i = 0; i < items.Length; i++)
        Console.Write("{0} ", items[i]);
      Console.WriteLine();
    }
  }

  class Program
  {
    static void Main(string[] args)
    {
      // Демонстрація роботи класу ArrayItems<T> для типу int
      int[] AI = { 2, 8, 3, 4, 11, 17, 5 };
      ArrayItems<int> A1 = new ArrayItems<int>(AI);

      A1.Print("A1:");

      // Додати елемент
      A1.AddValue(130);
      A1.Print("A1 + [130]:");

      // Видалити другий елемент
      A1.Delete(1);
      A1.Print("A1 - A1[1]:");

      // Замінити третій елемент
      A1.SetValue(111, 2);
      A1.Print("A1[2] = 111: ");

      // Зчитати елемент з індексом 4
      int item = A1.GetValue(4);
      Console.WriteLine("A1[4] = {0}", item);

      Console.ReadKey();
    }
  }
}

Результат виконання програми

A1:             2 8 3 4 11 17 5
A1 + [130]:             2 8 3 4 11 17 5 130
A1 - A1[1]:             2 3 4 11 17 5 130
A1[2] = 111:           2 3 111 11 17 5 130
A1[4] = 17

 

3. Приклад реалізації в класі узагальненого інтерфейсу для двох типів T1, T2

Оголошується інтерфейс MyInterface, що містить методи виведення даних типів T1, T2. У класі MyClass<T1, T2>, який реалізує цей інтерфейс, продемонстровано:

  • реалізацію методів інтерфейсу MyInterface<T1, T2>;
  • доступ до даних типів T1, T2.
using System;

namespace ConsoleApp19
{
  // Інтерфейс, що отримує два параметри типу T1, T2
  interface MyInterface<T1, T2>
  {
    // Оголошення методів, які використовують типи T1, T2
    void Print1(T1 var1);
    void Print2(T2 var2);
  }

  // Клас, що реалізує інтерфейс MyInterface<T1, T2>
  class MyClass<T1, T2> : MyInterface<T1, T2>
  {
    // Реалізація методу, що використовує тип T1
    public void Print1(T1 var1)
    {
      Console.WriteLine("var1 = {0}", var1);
    }

    // Реалізація методу, що використовує тип T2
    public void Print2(T2 var2)
    {
      Console.WriteLine("var2 = {0}", var2);
    }
  }

  class Program
  {
    static void Main(string[] args)
    {
      // 1. Оголосити екземпляр класу з типами-заповнювачами int, string
      MyClass<int, string> mc1 = new MyClass<int, string>();
      mc1.Print1(233);
      mc1.Print2("Hello world!");

      // 2. Оголосити екземпляр класу з типами-заповнювачами double, char
      MyClass<double, char> mc2 = new MyClass<double, char>();
      mc2.Print1(8.77);
      mc2.Print2('z');

      // 3. Реалізація для типів long, long
      MyClass<long, long> mc3 = new MyClass<long, long>();
      mc3.Print1(32323L);
      mc3.Print2(30000L);

      Console.ReadKey();
    }
  }
}

Результат виконання програми

var1 = 233
var2 = Hello world!
var1 = 8.77
var2 = z
var1 = 32323
var2 = 30000

 


Зв’язані теми