Шаблоны (Generics) в C#


Шаблоны. Звучит, как нечто очень далекое от программирования. Однако шаблоны являются крайне полезным инструментом. Фактически все динамические структуры в C# (динамические массивы, списки, очереди, стеки и пр) используют шаблонные методы. Также можно достаточно часто встретить и альтернативные названия такие как обобщенные типы, обобщения или generics.

Что такое шаблоны?

Предположим, необходимо разработать класс / метод, который работал бы с разными типами данных. Пока мы еще не знаем шаблонов, решением кажется создания отдельного метода для каждого типа данных. Другим решением может оказаться использование типа Object. Однако и подобный вариант крайне сомнителен: неудобен, небезопасен и нерационален с точки зрения использования памяти. Именно в данном случае следует использовать шаблоны. Синтаксис достаточно прост.

public void DoAny<T>(T val1, T val2, T val3);

В данном случае метод DoAny может обработать любой переданный ему тип данных. Буква T в треугольных скобках говорит о шаблонности метода. Следует заметить, что может быть использован любой другой символ. Однако общепринятым считается именно символ T (template - шаблон). Далее, эта буква будет меняться на тип данных, используемый нами при вызове метода. Использование шаблонных методов так же достаточно просто.

DoAny<int> (1, 2, 3); 

DoAny<char> ('a', 'b', 'c');

В треугольных скобках указывается тип данных, который будет использоваться при выполнении метода. Однако следует заметить, что такая попытка вызова метода

DoAny<string> ("a", 2, 3.14);

приведет к ошибке.

Пример Generics.

   /// <summary>
   /// Класс для демонстрации шаблонов.
   /// </summary>
   /// <typeparam name="T"> Тип данных.</typeparam>
   public class TemplateTest<T>
   {
       T[] arr = new T[10];
       int index = 0;

       /// <summary>
       /// Добавление элемента в массив.
       /// </summary>
       /// <param name="value"> Добавляемый элемент.</param>
       /// <returns> Был ли добавлен элемент.</returns>
       public bool Add(T value)
       {
           if (index >= 10)
           {
               return false;
           }

           arr[index++] = value;
           return true;
       }


       /// <summary>
       /// Получить элемент по индексу.
       /// </summary>
       /// <param name="index"> Индекс.</param>
       /// <returns> Элемент по индексу.</returns>
       public T get(int index)
       {
           if (index < this.index && index >= 0)
           {
               return arr[index];
           }
           else
           {
               return default(T);
           }
       }

       /// <summary>
       /// Получить количество элементов в массиве.
       /// </summary>
       /// <returns> Количество добавленных элементов.</returns>
       public int Count()
       {
           return index;
       }
   }

Мы создали шаблонный класс. Теперь мы можем использовать любой тип данных, при использовании описанного класса. Создавая конкретный объект следует указать используемый тип данных. Так, к примеру, мы можем создать массив как строк, так и чисел, а при желании можем указать другой класс.

var arrayInt = new TemplateTest<int>();

var arrayString = new TemplateTest<string>();

Однако далеко не всегда нам необходимо поддерживать все типы данных. Для этого достаточного указать ограничение шаблона при помощи ключевого слова where.

public class TemplateTest<T> where T: XXXXX

Здесь XXXXX может принимать одно из значений.

  • Class. Шаблон создается для классов, не объявленных как sealed.
  • struct. Использование шаблонов на основе структур.
  • new(). Параметр <T> должен быть классом, обладающим конструктором по умолчанию.
  • Имя_класса. Шаблон поддерживает использование типов данных, являющихся наследником указанного.
  • Имя_интерфейса. Использование классов, которые реализуют указанный интерфейс.

К примеру, при подобном объявлении класса.

public class TemplateTest<T> where T : int

Мы сможем использовать только целочисленный тип данных. Данный пример несколько лишен смысла, потому как начисто отсекает мощь шаблонов, однако отлично показывает, возможность ограничивать используемые типы данных.Полагаю, это необходимый минимум для использования шаблонов. Удачных вам экспериментов, коллеги. 

Источник Шаблоны C#


Comments 0