Приветствую всех, сегодня поговорим о джанериках. Джанерики это общий тип параметров.
Обобщение(Универсальные шаблоны) – элемент кода, способный адаптироваться для выполнения общих (сходных) действий над различными типами данных.
Универсальные шаблоны были добавлены в язык C# версии 2.0 и среду CLR. Эта возможность CTS (Common Type System — общая система типов), названа обобщениями (generics).
Его можно разделить на дви вида открытый и закрытий тип, открытый это <T> а закрытый может быть к примеру <int >или <string> Различие в том что мы устанавливаем ограничение в виде типа <int> <string>либо, компилятор сам разбирается какой ему тип будет передан.
1 2 3 4 |
class Types<T> { T[] mass = new T[5]; } |
1 2 3 4 |
static void Main() { Types<int> type = new Types<int>(); } |
Каждый закрытый тип получает свою собственную копию набора статических полей.
Обобщения обеспечивают большую производительность, так как не происходит операции «упаковки-распаковки»(Boxing-Unboxing).
С помощью ключевого слова default можно установить значение по умолчанию для ссылочного типа это будет null, для значений это 0.
1 2 3 4 5 |
public void Arr<T> (T[] array) { for (int i = 0; i < array.Length; i++) array[i] = default(T); } |
Разберем ограничения которые можно использовать в Generic Constraints
Эти ограничения применяются для того что не допустить ошибок при использования метода при передаче аргументов, так как программа не с компилируется в следствии чего программисту придется исправить код до компиляции по установленным требованиям. Однако стоит учитывать что одновременное использование некоторых ограничений не возможно.
1 2 3 4 5 6 7 8 9 10 |
public static void Sort<T>(T[] array) where T : IComparable //ограничение интерфейсом where T : new()//ограничение конструктором без параметров where T : struct //ограничение значимым типом where T : Sorter //ограничение ссылочным типом where T <strong>: </strong>class //относиться к классам, интерфейсам, делегатам { ... } |
Очень интересный пример, который благодаря именно ограничению позволил сделать это:
1 2 3 4 5 6 7 8 |
class MyClass<T> where T : new() { public static T FacrotyMethod() { return new T(); } } |
Если бы не ограничение конструктором без параметров, у нас бы возникла ошибка на стадии компиляции. Этот способ применяется при создании экземпляров, не известных типов.
А теперь посмотрим универсальный метод сортировки.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
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;
Однако не будем на этом останавливаться и сделаем общие расширение метода.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
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 параметров типов.
1 2 3 4 5 6 7 8 9 10 |
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 параметров типов.
1 2 3 4 5 6 7 8 9 10 11 |
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()); } |
Перегрузка обобщенных типов.
Перегрузки обобщенных типов различаются количеством параметров типа, а не их именами.
1 2 3 4 5 6 7 8 9 10 |
class MyClass<T> { T[] mass = new T[5]; } class MyClass<T,R> { T[] mass = new T[5]; R[] mass = new R[5]; } |
Общие сведения
Общие сведения об универсальных шаблонах:
- Используйте универсальные типы для достижения максимального уровня повторного использования кода, безопасности типа и производительности.
- Наиболее частым случаем использования универсальных шаблонов является создание классов коллекции.
- Можно создавать собственные универсальные интерфейсы, классы, методы,события и делегаты.
- Доступ универсальных классов к методам можно ограничить определенными типами данных.