
- •Лекция: Универсальность. Классы с родовыми параметрами Наследование и универсальность
- •Синтаксис универсального класса
- •Класс с универсальными методами
- •Родовое порождение класса. Предложение using
- •Универсальность и специальные случаи классов
- •Универсальные структуры
- •Универсальные интерфейсы
- •Универсальные делегаты
- •Framework .Net и универсальность
Родовое порождение класса. Предложение using
До сих пор рассматривалась ситуация родового порождения экземпляров универсального класса. Фактические типы задавались в момент создания экземпляра. Это наглядно показывает преимущества применяемой технологии, поскольку очевидно, что не создается дублирующий код для каждого класса, порожденного универсальным классом. И все-таки остается естественный вопрос: можно ли породить класс из универсального класса путем подстановки фактических параметров, а потом спокойно использовать этот класс обычным образом? Такая вещь возможна. Это можно сделать не совсем обычным путем - не в программном коде, а в предложении using, назначение которого и состоит в выполнении подобных подстановок.
Давайте вернемся к универсальному классу OneLinkStack<T>, введенному в начале этой лекции, и породим на его основе вполне конкретный классIntStack, заменив формальный параметрT фактическим -int. Для этого достаточно задать следующее предложениеusing:
using IntStack = Generic.OneLinkStack<int>;
Вот тест, в котором создаются несколько объектов этого класса:
public void TestIntStack()
{
IntStack stack1 = new IntStack();
IntStack stack2 = new IntStack();
IntStack stack3 = new IntStack();
stack1.put(11); stack1.put(22);
int x1 = stack1.item(), x2 = stack1.item();
if ((x1 == x2) && (x1 == 22)) Console.WriteLine("OK!");
stack1.remove(); x2 = stack1.item();
if ((x1 != x2) && (x2 == 11)) Console.WriteLine("OK!");
stack1.remove(); x2 = (stack1.empty()) ? 77 :
stack1.item();
if ((x1 != x2) && (x2 == 77)) Console.WriteLine("OK!");
stack2.put(55); stack2.put(66);
stack2.remove(); int s = stack2.item();
if (!stack2.empty()) Console.WriteLine(s);
stack3.put(333); stack3.put((int)Math.Sqrt(Math.PI));
int res = stack3.item();
stack3.remove(); res += stack3.item();
Console.WriteLine("res= {0}", res);
}
Универсальность и специальные случаи классов
Универсальность - это механизм, воздействующий на все элементы языка. Поэтому он применим ко всем частным случаям классов C# .
Универсальные структуры
Так же, как и обычный класс, структура может иметь родовые параметры. Синтаксис объявления, ограниченная универсальность, другие детали универсальности естественным образом распространяются на структуры. Вот типичный пример:
public struct Point<T>
{
T x, y;//координаты точки, тип которых задан параметром
// другие свойства и методы структуры
}
Универсальные интерфейсы
Интерфейсы чаще всего следует делать универсальными, предоставляя большую гибкость для позднейших этапов создания системы. Возможно, вы заметили применение в наших примерах универсальных интерфейсов библиотеки FCL - IComparable<T> и других. Введение универсальности, в первую очередь, сказалось на библиотеке FCL - внутренних классов, определяющих поведение системы. В частности, для большинства интерфейсов появились универсальные двойники с параметрами. Если бы в наших примерах мы использовали не универсальный интерфейс, а обычный, то потеряли бы в эффективности, поскольку сравнение объектов потребовало бы создание временных объектов типаobject, выполнения операцийboxing иunboxing.