Обобщения. Появились .Net 2.0
Пример: List customerList = newList<myCustomer>(); Типизированный список для хранения объектов типа Заказчик.
Обобщения создают классы и методы, независимые от хранящихся в них типов.
Для разных типов данных с одной функциональностью создается один обобщенный класс.
Обобщения касаются классов, методов, интерфейсов и делегатов.
Производительность и безопасность.
Использование типа Object для этих целей небезопасно тк проверка типа выполняется во время выполнения а не при компиляции и медленно из-за запаковки (boxing - когда простой стэковый тип значения приводится к объектному ссылочному типу) и распаковки (unboxing– когда хранящийся в объекте (в куче) тип значения переводится обратно в стэковую переменную ).
Размер машинного кода.
.Net JIT компилятор в машинный код выполняет аппаратную оптимизацию тк ему известен тип процессора и архитектура.
Для типов значения: При JIT компиляции в машинный код из одного обобщенного класса для каждого типа значения создается отдельный класс тк у элементов типов значения разная длина.
Для всех ссылочных типов: создается один экземпляр класса тк все указатели на элементы в памяти занимают 32 (64) бита.
Значения по умолчанию и ограничения
usingSystem;
usingSystem.Collections.Generic;
usingSystem.Linq;
usingSystem.Text;
namespace orderManager
{
class Program
{
static void Main(string[] args)
{
var om = new OrderManager<Order>();
om.AddOrder(new Order("1", "Ivanov"));
om.AddOrder(new Order("2", "Petrov"));
om.DisplayAllOrders();
if (om.IsOrderAvailable)
{
Order o = om.GetOrder();
Console.WriteLine(o.OrderNo);
}
Console.ReadLine();
}
}
// создается для чтения и записи заказов в очереди
// public class OrderManager<T> - реализация обобщенного типа
public class OrderManager<TOrder> //реализация ограничения типа,
where TOrder : IOrder //который обязан реализовать интерфейс
{
private readonly Queue<TOrder> orderQueue = new Queue<TOrder>();
public void AddOrder(TOrder order) { lock (this) { orderQueue.Enqueue(order); } }
public bool IsOrderAvailable { get { return orderQueue.Count > 0; } }
public TOrder GetOrder()
{
TOrder order = default(TOrder); // ссылочные типы инициализирутся NULL
// а типы значения - 0
lock (this) { order = orderQueue.Dequeue(); }
return order;
}
/*
public void DisplayAllOrders()
{
foreach (T ord in orderQueue) {
Console.WriteLine(((IOrder)ord).OrderNo); //если T не реализует интефейс IOrder -
// ошибка времени выполнения
}
}
*/
public void DisplayAllOrders()
{
foreach (TOrder ord in orderQueue)
{ Console.WriteLine("№"+ord.OrderNo+ " Customer: "+ord.CustName); }
}
}
// создается для гарантии присутствия требуемых свойств и методов в классе заказа
public interface IOrder
{
string OrderNo { get; set; }
stringCustName { get; set; }
}
// создается для хранения одного заказа
publicclass Order : IOrder
{
private string orderNo = string.Empty;
private string custName = string.Empty;
public string OrderNo { get { return orderNo; } set { orderNo = value; } }
public string CustName { get { return custName; } set { custName = value; } }
public Order() {}
public Order(string no, string customerName) {orderNo = no; custName = customerName; }
}
}
Ограничения, поддерживаемые обобщениями
|
Ограничение
|
Описание
|
|
where T : struct
|
T – тип значения
|
|
where T : class
|
Т – ссылочный тип
|
|
where T : IFoo
|
Т – реализует интерфейс
|
|
where T : Foo
|
Т – наследует класс
|
|
where T : new()
|
Т – д.б. конструктор по умолчанию
|
|
whereT1 : T2
|
Т1 наследует обобщенный тип Т2
|
Ограничения объединяются через запятую.
Наследование
Дочерний класс от обобщенного м.б. обобщенным или нет.
publicabstract class Calc<T>
{ public abstract T Add(T x, T y); }
public class IntCalc : Calc<int>
{
public override int Add(int x, int y) { return x + y; }
}
Статические члены
Разделяются одним экземпляром класса. Таким образом:
public class StaticDemo<T> { public static int x; }
StaticDemo<string>.x = 4;
StaticDemo<int>.x = 5;
Console.WriteLine(StaticDemo<string>.x); // 4
Обобщенные интерфейсы
public interface IComparable<T> { int CompareTo(T other); }
public class Person : IComparable<Person>
{
public int CompareTo(Person other)
{
return this.LastName.CompareTo(other.LastName);
}
..
}