Новинки языка C#.NET
Страница 2. Общие типы (Generics)


 

Общие типы (Generics)

Общие (или параметризованные) типы (generics) позволяют при описании классов, структур, методов и интерфейсов использовать параметризованные параметры (не указывать тип параметра в момент написания кода). Тип параметра определяется в момент объявления переменной соответствующего типа. Таким образом можно создать некоторый общий элемент, тип который можно использовать в дальнейшем для данных различных типов. Программисты на C++ могут углядеть с общих типах сходство с шаблонами (templates), в чем-то эта аналогия будет верна, но тут существуют некоторые ограничения, которые мы рассмотрим чуть позднее.

Объяснение получилось несколько сумбурным, поэтому будет лучше рассмотреть простые и понятные примеры. Прежде всего создадим класс используя общие типы:

class Generics<TYPE1, TYPE2>
{
  private TYPE1 mVar1;
  private TYPE2 mVar2;
  public Generics(TYPE1 Var1, TYPE2 Var2)
   {
    this.mVar1 = Var1;
    this.mVar2 = Var2;
   }
  public string ToStringFunction(string Delemiter)
   {
    return this.mVar1.ToString() + Delemiter + this.mVar2.ToString();
   }
  public TYPE1 Variable1
   {
       get
       {
      return this.mVar1;
       }
       set
       {
      this.mVar1 = value;
       }
   }
  public TYPE2 Variable2
   {
       get
       {
      return this.mVar2;
       }
       set
       {
      this.mVar2 = value;
       }
   }
}

Как видно из примера, для того чтобы использовать общие типы нужно после объявления класса указать параметризованные типы: Generics<TYPE1, TYPE2> объявляет класс с двумя параметризованными типами. Теперь используем написанный класс:

// объявление
Generics<string, string> strGeneric = new Generics<string, string>("Hello","world");
Generics<int, int> intGeneric = new Generics<int,int>(1, 2);
Generics<string, int> strintGeneric = new Generics<string,int>("Three", 3);
int intSum;
string strSum;
// использование
intSum = intGeneric.Variable1 + intGeneric.Variable2;
strSum = strintGeneric.Variable1 + " " + strintGeneric.Variable2.ToString();
MessageBox.Show("\nstrGeneric:\n" + strGeneric.Variable1 + " " + strGeneric.Variable2 +
"\n\nintGeneric sum:\n" + intSum.ToString() +
"\n\nstrintGeneric sum:\n" + strSum.ToString());  

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

public struct GenericStruct<TYPE>
{
  public TYPE someField;
}
public interface IGeneric<TYPE>
{
  TYPE SomeMethod();
  TYPE AnotherMethod();
}

Более того, параметризованные типы могут быть использованы при объявлении делегатов функций. Продемонстрирую эту возможность используя объявленный выше класс Generics.

// Объявляем делегат
public delegate DELEGATETYPE GenericDelegate<DELEGATETYPE, PARAMTYPE> (PARAMTYPE Param);
// используем делегат
Generics<string, string> strGeneric = new Generics<string, string>("Hello", "world");
GenericDelegate<string, string> genDelegate =
new GenericDelegate<string, string>(strGeneric.ToStringFunction);
// вызов делагата
MessageBox.Show(genDelegate(" my "));

Преимущества использования общих типов

"Вау!" - воскликнут программисты на C++ использующие в своей работе также и C#. "И что нам с того?" - скажут программисты на C# никогда не работавшие с шаблонами С++. Какие же преимущества дает использование общих типов?

  1. Наиболее очевидное - повторное использование кода. Нет необходимости создавать два идентичных класса, отличающихся только типами параметров, достаточно создать один с параметризованными типами. При этом использование параметризованных типов позволяет создавать единый программный код для работы с различными типами данных. Например, единожды написанный алгоритм может работать и с целыми числами и с числами с плавающей десятичной точкой, при этом не производя на каждом шаге проверку/приведение типа. Так Generics вытесняют классы объявленные с использованием типа object.

  2. Повышение производительности кода по сравнению с использование параметров типа object - нет необходимости выполнять приведение, как уже сказано выше, на каждом шаге, за счет чего получается выигрыш в производительности.

  3. Проверка типов в момент компиляции программы. Поскольку не используются параметры типа object, то компилятор может выполнить проверку типа каждого параметра в момент компиляции, поскольку типы для Generic классов жестко задаются в момент объявления переменных классов этого типа.

К сожалению, опытных программистов на C++ я должен несколько расстроить. Общие типы все-таки не соответствуют шаблонам в C++, поскольку параметризованные типы в C# не могут иметь типов по умолчанию. Параметризованные типы не могут быть использованы в качестве базовых классов для общих типов. Также в C# не допускается использования Generic классов в качестве параметров типов в других Generic классах.

Но, несмотря на это, общие типы все-таки весьма полезным новшеством языка C#, особенно ценным и удобным для разработчиков использующих математические алгоритмы, поскольку преимущества использования Generic классов очевидны.

 
Следующая статья »