Разбираемся с обобщением generic

Приветствую всех, сегодня поговорим о джанериках.  Джанерики это общий тип параметров.

Обобщение(Универсальные шаблоны) – элемент кода, способный адаптироваться для выполнения общих (сходных) действий над различными типами данных.
Универсальные шаблоны были добавлены в язык 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];
}

Общие сведения

Общие сведения об универсальных шаблонах:

  • Используйте универсальные типы для достижения максимального уровня повторного использования кода, безопасности типа и производительности.
  • Наиболее частым случаем использования универсальных шаблонов является создание классов коллекции.
  • Можно создавать собственные универсальные интерфейсы, классы, методы,события и делегаты.
  • Доступ универсальных классов к методам можно ограничить определенными типами данных.

 

 

Обновлено: 23.03.2018 — 17:21

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Этот сайт использует Akismet для борьбы со спамом. Узнайте, как обрабатываются ваши данные комментариев.