На этом шаге мы рассмотрим использование этих классов при наследовании.
Рассмотренный на предыдущем шаге механизм реализации обобщенных интерфейсов применим и к наследованию классов. Идея очень простая: один класс может наследовать другой класс, даже если последний является обобщенным. При этом производный класс может быть как обобщенным, так и обычным. В программе ниже приведен пример, похожий на пример из предыдущего шага, но вместо реализации интерфейса задействовано наследование обобщенного абстрактного класса.
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace pr261_1 { // Обобщенный абстрактный класс: abstract class MyClass<X,Y> { // Поля обобщенного типа: protected X first; protected Y second; // Абстрактные методы: abstract public void set(X a,Y b); abstract public void show(); } // Обобщенный класс наследует обобщенный абстрактный класс: class Alpha<X,Y>: MyClass<X,Y> { public override void set(X a,Y b) { first = a; second = b; } public override void show() { Console.WriteLine("Поля {0} и {1}", first, second); } } // Обобщенный класс наследует обобщенный абстрактный класс: class Bravo<Y>: MyClass<int, Y> { public override void set(int a, Y b) { first = a; second = b; } public override void show() { Console.WriteLine("Поля {0} и {1}", first, second); } } // Обычный класс наследует обобщенный абстрактный класс: class Charlie: MyClass<int, char> { public override void set(int a, char b) { first = a; second = b; } public override void show() { Console.WriteLine("Поля {0} и {1}", first, second); } } // Главный класс: class Program { // Главный метод: static void Main() { Console.WriteLine("Первый объект"); // Создание объекта на основе обобщенного класса: Alpha<string, double> A = new Alpha<string, double>(); // Использование объектной переменной базового // абстрактного класса: MyClass<string, double> Ra = A; // Вызов методов: A.set("Alpha", 100.0); Ra.show(); Ra.set("alpha", 150.0); A.show(); Console.WriteLine("Второй объект"); // Создание объекта на основе обобщенного класса: Bravo<string> B = new Bravo<string>(); // Использование объектной переменной базового // абстрактного класса: MyClass<int, string> Rb = B; // Вызов методов: B.set(200, "Bravo"); Rb.show(); Rb.set(250, "bravo"); B.show(); Console.WriteLine("Tpeтий объект"); // Создание объекта на основе обычного класса: Charlie C = new Charlie(); // Использование объектной переменной базового // абстрактного класса: MyClass<int, char> Rc = C; // Вызов методов: C.set(300, 'С'); Rc.show(); Rc.set(350, 'D'); C.show(); // Задержка: Console.ReadLine(); } } }
Результат выполнения программы совпадает с результатом работы программы из предыдущего шага:
Рис.1. Результат работы приложения
В этой программе мы описали абстрактный обобщенный класс MyClass с двумя обобщенными параметрами (обозначены как X и Y). В классе объявлены два protected-поля first и second обобщенных типов, а также абстрактные методы set() и show(). Классы Alpha, Bravo и Charlie наследуют (но по-разному) абстрактный базовый класс MyClass. В производных класса переопределяются методы set() и show(). В главном методе программы создаются объекты классов Alpha, Bravo и Charlie, а также проверяется работа методов set() и show().
На следующем шаге мы рассмотрим обобщенные делегаты.