C#. Generic interfaces. Declaration syntax

Generic interfaces. Declaration syntax. Implementing generic interfaces in classes. Examples

Before exploring this topic, it is recommended that you familiarize yourself with the following topic:


Contents


Search other resources:




1. Syntax for declaring a generic interface

In C#, it is allowed to declare generic interfaces. When declaring a generic interface, the signature of methods that are declared in the interface can contain references to parameterized types. The list of parameterized types (for example T1, T2, …, TN) is specified in the header of the interface declaration between the <> symbols.

The general form of declaring a generic interface is as follows:

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

here

  • InterfaceName – interface name;
  • T1, T2, TN – type names that act as interface parameters.

A class that implements the InterfaceName<T1, T2, …, TN> interface must be declared as follows:

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

here

  • ClassName – the name of the class that implements InterfaceName.

In the simplest case, the interface receives some type T. In this case, the general form of the interface declaration and its implementation in the class is as follows

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

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

 

2. Examples of implementation of a generic interface for a single type T
2.1. Implementation of basic operations on numbers: addition, subtraction

The example declares a generic interface that receives the type T as a parameter. The interface implements the addition and subtraction numbers.

using System;

namespace ConsoleApp19
{
  // An interface that receives two parameters of type T
  interface Operations<T>
  {
    // Declaring methods that use type T
    double Add(T var1, T var2);
    double Sub(T var1, T var2);
  }

  // Class, that implements MyInterface<T1, T2> interface
  class MyClass<T> : Operations<T>
  {
    // Implementation of a method that uses type 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)
    {
      // Demonstration of using a generic interface
      // 1. For placeholder int type
      MyClass<int> mc1 = new MyClass<int>();
      double res1 = mc1.Add(23, 48);
      Console.WriteLine("res1 = {0}", res1);

      // 2. For placeholder float type
      MyClass<float> mc2 = new MyClass<float>();
      double res2 = mc2.Sub(8.804f, 1.704f);
      Console.WriteLine("res2 = {0:f}", res2);

      Console.ReadKey();
    }
  }
}

The result of the program

res1 = 71
res2 = 10.51

 

2.2. Implementation of methods for processing a data array

Declare a generic interface IItems<T> containing the following methods for processing an array of data of type T:

  • Count() – returns the number of elements in the array;
  • GetValue() – get an element by its index;
  • SetValue() – set a new element at the specified index;
  • AddValue() – add an element to the end of the array;
  • Delete() – delete an element from a given position.

Declare a generic class ArrayItems<T> that implements the IItems<T> interface. In addition to interface methods in the class, additionally implement:

  • array of data of type T[];
  • constructor without a parameters;
  • a constructor with a parameter that receives another array of type T[];
  • the Print() method, which outputs the array in a viewable form.

The program text that solves this problem is as follows:

using System;

namespace ConsoleApp19
{
  // Generalized interface for an array of elements of different types
  interface IItems<T>
  {
    // The number of elements in the array
    int Count();

    // Receive the item by it's index
    T GetValue(int index);

    // Set a new item at the specified index
    void SetValue(T value, int index);

    // Add an element to the end of the array
    void AddValue(T value);

    // Remove element from position index
    void Delete(int index);
  }

  // Class that implements IItems<T> interface
  class ArrayItems<T> : IItems<T>
  {
    // Internal array
    T[] items;

    // Constructors
    public ArrayItems()
    {
      // Set default value
      items = default(T[]);
    }

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

    // Method that returns the number of elements in the array
    public int Count()
    {
      return items.Length;
    }

    // Get the item by it's index
    public T GetValue(int index)
    {
      return items[index];
    }

    // Set a new value by it's index
    public void SetValue(T value, int index)
    {
      // Checking if the index is within acceptable limits
      if ((index>=0)&&(index<items.Length))
        items[index] = value;
    }

    // Add item to the end of array
    public void AddValue(T value)
    {
      // Remember the reference to the old array
      T[] items2 = items;

      // Create a new array
      items = new T[items.Length + 1];

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

      // Add the last item
      items[items.Length - 1] = value;
    }

    // Remove the item at the position index
    public void Delete(int index)
    {
      // Checking the index for correctness
      if ((index < 0) || (index >= items.Length))
        return;

      // Create a new array with 1 less length
      T[] items2 = new T[items.Length - 1];

      // Copy elements bypassing the index position
      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];

      // Redirect internal reference
      items = items2;
    }

    // Displaying the array to the screen
    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)
    {
      // Demonstration of the ArrayItems<T> class for int type
      int[] AI = { 2, 8, 3, 4, 11, 17, 5 };
      ArrayItems<int> A1 = new ArrayItems<int>(AI);
      A1.Print("A1:");

      // Add item
      A1.AddValue(130);
      A1.Print("A1 + [130]:");

      // Delete last item
      A1.Delete(1);
      A1.Print("A1 - A1[1]:");

      // Replace third item
      A1.SetValue(111, 2);
      A1.Print("A1[2] = 111: ");

      // Read the item at index 4
      int item = A1.GetValue(4);
      Console.WriteLine("A1[4] = {0}", item);

      Console.ReadKey();
    }
  }
}

The result of the program

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. An example of implementation in a class of a generic interface for two types T1, T2

The MyInterface interface is declared, which contains methods for outputting data of types T1, T2. The class MyClass<T1, T2>, which implements this interface, demonstrates:

  • implementation of methods of interface MyInterface<T1, T2>;
  • access to data of types T1, T2.
using System;

namespace ConsoleApp19
{
  // An interface that receives two parameters of type T1, T2
  interface MyInterface<T1, T2>
  {
    // Declaring methods using types T1, T2
    void Print1(T1 var1);
    void Print2(T2 var2);
  }

  // Class that implements MyInterface<T1, T2> interface
  class MyClass<T1, T2> : MyInterface<T1, T2>
  {
    // Implementation of the method that uses a type T1
    public void Print1(T1 var1)
    {
      Console.WriteLine("var1 = {0}", var1);
    }

    // Implementation of the method that uses a type T2
    public void Print2(T2 var2)
    {
      Console.WriteLine("var2 = {0}", var2);
    }
  }

  class Program
  {
    static void Main(string[] args)
    {
      // 1. Declare an instance of a class with placeholders int, string
      MyClass<int, string> mc1 = new MyClass<int, string>();
      mc1.Print1(233);
      mc1.Print2("Hello world!");

      // 2. Declare an instance of a class with placeholder types double, char
      MyClass<double, char> mc2 = new MyClass<double, char>();
      mc2.Print1(8.77);
      mc2.Print2('z');

      // 3. Implementation for types long, long
      MyClass<long, long> mc3 = new MyClass<long, long>();
      mc3.Print1(32323L);
      mc3.Print2(30000L);

      Console.ReadKey();
    }
  }
}

The result of the program

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

 


Related topics