// Простая иерархия обобщенных классов, using System;
// Обобщенный базовый класс, class Gen<T> {
Т ob;
public Gen(Т о) { ob = о;
}
// Возвратить значение переменной ob. public Т GetOb() { return ob;
}
}
// Класс, производный от класса Gen. class Gen2<T>: Gen<T> {
public Gen2(T o): base(o) {
II...
}
class GenHierDemo { static void Main() {
Gen2<string> g2 = new Gen2<string>("Привет");
Console.WriteLine(g2.GetOb());
В этой иерархии класс Gen 2 наследует от обобщенного класса Gen. Обратите внимание на объявление класса Gen 2 в следующей строке кода.
class Gen2<T>: Gen<T> {
Параметр типа Т указывается в объявлении класса Gen2 и в то же время передается классу Gen. Это означает, что любой тип, передаваемый классу Gen2, будет передаваться также классу Gen. Например, в следующем объявлении:
Gen2<string> g2 = new Gen2<string>("Привет");
Параметр типа string передается классу Gen. Поэтому переменная ob в той части класса Gen2, которая относится к классу Gen, будет иметь тип string.
Обратите также внимание на то, что в классе Gen2 параметр типа Т не используется, а только передается вверх по иерархии базовому классу Gen. Это означает, что в производном классе следует непременно указывать параметры типа, требующиеся его обобщенному базовому классу, даже если этот производный класс не обязательно должен быть обобщенным.
Разумеется, в производный класс можно свободно добавлять его собственные параметры типа, если в этом есть потребность. В качестве примера ниже приведен вариант предыдущей иерархии классов, где в класс Gen2 добавлен собственный параметр типа.
// Пример добавления собственных параметров типа в производный класс, using System;
// Обобщенный базовый класс, class Gen<T> {
Т ob; // объявить переменную типа Т
// Передать конструктору ссылку типа Т. public Gen(T о) { ob = о;
}
// Возвратить значение переменной ob. public Т GetOb () {
Return ob;
}
}
// Класс, производный от класса Gen. В этом классе // определяется второй параметр типа V. class Gen2<T, V>: Gen<T> {
V ob2;
public Gen2(T о, V o2): base (o) {
ob2 = o2;
}
public V Get0bj2() { return ob2;
' }
}
11 Создать объект класса Gen2. class GenHierDemo2 { static void Main() {
// Создать объект класса Gen2 с параметрами // типа string и int.
Gen2<string, in.t> x =
new Gen2<string, int>("Значение равно: ", 99);
Console.Write(x.GetOb());
Console.WriteLine(x.GetObj2());
}
}
Обратите внимание на приведенное ниже объявление класса Gen2 в данном варианте иерархии классов.
class Gen2<T, V>: Gen<T> {
В этом объявлении Т — это тип, передаваемый базовому классу Gen; а V — тип, характерный только для производного класса Gen2. Он служит для объявления объекта оЬ2 и в качестве типа, возвращаемого методом GetOb j 2 (). В методе Main () создается объект класса Gen2 с параметром Т типа string и параметром V типа int. Поэтому код из приведенного выше примера дает следующий результат.
Значение равно: 99
Обобщенный производный класс
Необобщенный класс может быть вполне.законно базовым для обобщенного производного класса. В качестве примера рассмотрим следующую программу.
// Пример необобщенного класса в качестве базового для // обобщенного производного класса.
Using System;
// Необобщенный базовый класс, class NonGen { int num;
public NonGen(int i) { num = i;
}
public int GetNum() { return num;
}
}
// Обобщенный производный класс, class Gen<T>: NonGen {
T ob;
public Gen(T о, int i): base (i) {
ob = o;
}
// Возвратить значение переменной ob. public T GetOb() { return ob;
}
}
// Создать объект класса Gen. class HierDemo3 {
static void Main() {
// Создать объект класса Gen с параметром типа string.
Gen<String> w = new Gen<String>("Привет", 47);
Console.Write(w.GetOb() + " ");
Console.WriteLine(w.GetNum());
}
}
Эта программа дает следующий результат.
Привет 47
В данной программе обратите внимание на то, как класс Gen наследует от класса NonGen в следующем объявлении.
class Gen<T>: NonGen {
Класс NonGen не является обобщенным, и поэтому аргумент типа для него не указывается. Это означает, что параметр Т, указываемый в объявлении обобщенного производного класса Gen, не требуется для указания базового класса NonGen и даже не может в нем использоваться. Следовательно, класс Gen наследует от класса NonGen обычным образом, т.е. без выполнения каких-то особых условий.
Переопределение виртуальных методов в обобщенном классе
В обобщенном классе виртуальный метод может быть переопределен таким же образом, как и любой другой метод. В качестве примера рассмотрим следующую программу, в которой переопределяется виртуальный метод GetOb ().
// Пример переопределения виртуального метода в обобщенном классе, using System;
// Обобщенный базовый класс, class 'Gen<T> { protected Т ob;
public Gen(T о) { ob = о;
}
// Возвратить значение переменной ob. Этот метод является виртуальным.
public virtual T GetOb () {
Console.Write("Метод GetOb () из класса Gen" + " возвращает результат: "); return ob;
}
}
// Класс, производный от класса Gen. В этом классе // переопределяется метод GetOb (). class Gen2<T>: Gen<T> {
public Gen2 (T o): base(o) { }
// Переопределить метод GetOb(). public override T GetOb() {
Console.Write("Метод GetOb() из класса Gen2" + " возвращает результат: "); return ob;
}
}
// Продемонстрировать переопределение метода в обобщенном классе, class OverrideDemo { static void Main() {
// Создать объект класса Gen с параметром типа int.
Gen<int> iOb = new Gen<int>(88);
// Здесь вызывается вариант метода GetOb() из класса Gen.