Приветствую всех, сегодня поговорим о джанериках. Джанерики это общий тип параметров.
Обобщение(Универсальные шаблоны) – элемент кода, способный адаптироваться для выполнения общих (сходных) действий над различными типами данных.
Универсальные шаблоны были добавлены в язык C# версии 2.0 и среду CLR. Эта возможность CTS (Common Type System — общая система типов), названа обобщениями (generics).
Его можно разделить на дви вида открытый и закрытий тип, открытый это <T> а закрытый может быть к примеру <int >или <string> Различие в том что мы устанавливаем ограничение в виде типа <int> <string>либо, компилятор сам разбирается какой ему тип будет передан.
class Types<T>
{
T[] mass = new T[5];
}
static void Main()
{
Types<int> type = new Types<int>();
}
Каждый закрытый тип получает свою собственную копию набора статических полей.
Обобщения обеспечивают большую производительность, так как не происходит операции «упаковки-распаковки»(Boxing-Unboxing).
С помощью ключевого слова default можно установить значение по умолчанию для ссылочного типа это будет null, для значений это 0.
public void Arr<T> (T[] array)
{
for (int i = 0; i < array.Length; i++)
array[i] = default(T);
}
Разберем ограничения которые можно использовать в Generic Constraints
Эти ограничения применяются для того что не допустить ошибок при использования метода при передаче аргументов, так как программа не с компилируется в следствии чего программисту придется исправить код до компиляции по установленным требованиям. Однако стоит учитывать что одновременное использование некоторых ограничений не возможно.
public static void Sort<T>(T[] array)
where T : IComparable //ограничение интерфейсом
where T : new()//ограничение конструктором без параметров
where T : struct //ограничение значимым типом
where T : Sorter //ограничение ссылочным типом
where T : class //относиться к классам, интерфейсам, делегатам
{
...
}
Очень интересный пример, который благодаря именно ограничению позволил сделать это:
class MyClass<T> where T : new()
{
public static T FacrotyMethod()
{
return new T();
}
}
Если бы не ограничение конструктором без параметров, у нас бы возникла ошибка на стадии компиляции. Этот способ применяется при создании экземпляров, не известных типов.
А теперь посмотрим универсальный метод сортировки.
class Program
{
static void Main()
{
var intArray = new int[] { 1, 2, 3 };
Sorter.Sort(intArray); //T автоматически выводится из типа переданного массива
}
}
public class Sorter
{
//Это - дженерик метод. Компилятор превращает его в обычный метод
//внутри дженерик-класса (то есть так, как написано выше)
public static void Sort<T>(T[] array)
where T : IComparable
{
for (int i = array.Length - 1; i > 0; i--)
for (int j = 1; j <= i; j++)
{
var element1 = array[j - 1];
var element2 = array[j];
if (element1.CompareTo(element2) < 0)
{
array[j - 1] = element2;
array[j] = element1;
}
}
}
}
Мы использовали джанерики тем самым, избежали конкретизации в применении метода Sort() который примет любой массив не зависимо от его типа и отсортирует его. Однако на него наложено ограничения, массив должен реализовывать интерфейс IComparable;
Однако не будем на этом останавливаться и сделаем общие расширение метода.
class Program
{
static void Main()
{
var intArray = new int[] { 1, 2, 3 };
intArray.BubbleSort();
}
}
public static class Sorter
{
//А это - generic extension метод
public static void BubbleSort<T>(this T[] array)
where T : IComparable
{
for (int i = array.Length - 1; i > 0; i--)
for (int j = 1; j <= i; j++)
{
var element1 = array[j - 1];
var element2 = array[j];
if (element1.CompareTo(element2) < 0)
{
array[j - 1] = element2;
array[j] = element1;
}
}
}
}
Мы изменили метод так что он теперь будет доступен из всех переменных реализующий интерфейс IComparable.
Upcast
Ковариантность обобщений – UpCast параметров типов.
class Animal { }
class Cat : Animal { }
delegate T MyDelegate<out T>();
static void Main()
{
MyDelegate<Cat> delegateCat = () => new Cat();
MyDelegate<Animal> delegateAnimal = delegateCat;
Animal animal = delegateAnimal.Invoke();
Console.WriteLine(animal.GetType().Name);
}
Ковариантность обобщений в C# 4.0 ограничена интерфейсами и делегатами.
DownCast
Контрвариантность обобщений – DownCast параметров типов.
class Animal { }
class Cat : Animal { }
delegate void MyDelegate<in T>(T a);
static void Main()
{
MyDelegate<Animal> delegateAnimal = (Animal animal) =>
Console.WriteLine(animal.GetType().Name);
MyDelegate<Cat> delegateCat = delegateAnimal;
delegateAnimal(new Animal());
delegateCat(new Cat());
}
Перегрузка обобщенных типов.
Перегрузки обобщенных типов различаются количеством параметров типа, а не их именами.
class MyClass<T>
{
T[] mass = new T[5];
}
class MyClass<T,R>
{
T[] mass = new T[5];
R[] mass = new R[5];
}
Общие сведения
Общие сведения об универсальных шаблонах:
- Используйте универсальные типы для достижения максимального уровня повторного использования кода, безопасности типа и производительности.
- Наиболее частым случаем использования универсальных шаблонов является создание классов коллекции.
- Можно создавать собственные универсальные интерфейсы, классы, методы,события и делегаты.
- Доступ универсальных классов к методам можно ограничить определенными типами данных.
