Книга: C# 4.0: полное руководство

Иерархии обобщенных классов

Иерархии обобщенных классов

Обобщенные классы могут входить в иерархию классов аналогично необобщенным классам. Следовательно, обобщенный класс может действовать как базовый или производный класс. Главное отличие между иерархиями обобщенных и необобщенных классов заключается в том, что в первом случае аргументы типа, необходимые обобщенному базовому классу, должны передаваться всеми производными классами вверх по иерархии аналогично передаче аргументов конструктора.

Применение обобщенного базового класса

Ниже приведен простой пример иерархии, в которой используется обобщенный базовый класс.

// Простая иерархия обобщенных классов,
using System;
// Обобщенный базовый класс,
class Gen<T> {
  T ob;
  public Gen(T о) {
    ob = о;
  }
  // Возвратить значение переменной ob.
  public T GetOb() {
    return ob;
  }
}
// Класс, производный от класса Gen.
class Gen2<T> : Gen<T> {
  public Gen2(T o) : base(o) {
    // ...
  }
}
class GenHierDemo {
  static void Main() {
    Gen2<string> g2 = new Gen2<string>("Привет");
    Console.WriteLine(g2.GetOb());
  }
}

В этой иерархии класс Gen2 наследует от обобщенного класса Gen. Обратите внимание на объявление класса Gen2 в следующей строке кода.

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> {
  T ob; // объявить переменную типа Т
  // Передать конструктору ссылку типа Т.
  public Gen(T о) {
    ob = о;
  }
  // Возвратить значение переменной ob.
  public T GetOb() {
    return ob;
  }
}
// Класс, производный от класса Gen. В этом классе
// определяется второй параметр типа V.
class Gen2<T, V> : Gen<T> {
  V ob2;
  public Gen2(T o, V o2) : base(o) {
    ob2 = o2;
  }
  public V GetObj2() {
    return ob2;
  }
}
// Создать объект класса Gen2.
class GenHierDemo2 {
  static void Main() {
    // Создать объект класса Gen2 с параметрами
    // типа string и int.
    Gen2 < string, int > x =
             new Gen2<string, int>("Значение равно: ", 99);
    Console.Write(x.GetOb());
    Console.WriteLine(x.GetObj2());
  }
}

Обратите внимание на приведенное ниже объявление класса Gen2 в данном варианте иерархии классов.

class Gen2<T, V> : Gen<T> {

В этом объявлении Т — это тип, передаваемый базовому классу Gen; а V — тип, характерный только для производного класса Gen2. Он служит для объявления объекта оb2 и в качестве типа, возвращаемого методом GetObj2(). В методе 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 o, 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 обычным образом, т.е. без выполнения каких-то особых условий.

Оглавление книги


Генерация: 5.711. Запросов К БД/Cache: 3 / 0
поделиться
Вверх Вниз