Чтобы научиться интегрировать обобщения в проекты, мы начнем с простого примера обычной подпрограммы свопинга. Целью этого примера является построение метода обмена, который сможет работать c любыми типами данных (характеризуемыми значениями или ссылками), используя для этого один параметр типа. В силу самой природы алгоритмов свопинга входные параметры будут посылаться по ссылке (с помощью ключевого слова C# ref). Вот соответствующая полная реализация.
// Этот метод переставляет любые два элемента,
// определенные параметром типа ‹Т›.
static void Swap‹T›(ref T a, ref Т b) {
Console.WriteLine ("Методу Swap () передано {0}", typeof(T));
Т temp;
temp = а;
а = b;
b = temp;
}
Обратите внимание на то, что обобщенный метод определяется с помощью указания параметра типа, размещаемого после имени метода, но перед списком параметров. Здесь вы заявляете, что метод Swap() может работать с любыми двумя параметрами типа ‹Т›. Просто для информации вы выводите имя типа соответствующего заменителя на консоль с помощью оператора C# typeof(). Теперь рассмотрите следующий метод Main(), в котором происходит обмен между целочисленными и строковыми типами.
static void Main(string[] args) {
Console.WriteLine("***** Забавы с обобщениями *****\n")
// Обмен между двумя целыми.
int а = 10, b = 90;
Console.WriteLine("До обмена: {0}, {l}", а, b);
Swap‹int›(ref a, ref b);
Console.WriteLine("После обмена: {0}, {1}", а, b);
Console.WriteLine();
// Обмен между двумя строками.
string s1 = "Hello", s2 = "There";
Console.WriteLine("До обмена: {0} {1}!", s1, s2);
Swap‹string›(ref s1, ref s2);
Console.WriteLine("После обмена: {0} {1}!", s1, s2);
Console.ReadLine();
}
Пропуск параметров типа
При вызове обобщенных методов, подобных Swap‹T›, у ваc есть возможность не указывать параметр типа, но только в том случае, когда обобщенный метод требует указания аргументов, поскольку тогда компилятор может "выяснить" тип этих аргументов на основе вводимых параметров. Например, можно переставить два типа System.Boolean так.
// Компилятор будет предполагать System.Boolean.
bool b1 = true, b2 = false;
Console.WriteLine("До обмена: {0}, {1}", b1, b2);
Swap(ref b1, ref b2);
Console.WriteLine("После обмена: {0}, {1}", b1, b2);
Но если, например, у вас есть обобщённый метод с именем DisplayBaseClass‹T›, не имеющий входных параметров, как показано ниже:
static void DisplayBaseClass‹T›() {
Console.WriteLine("Базовым классом {0} является: {1}.", typeof(T), typeof(Т).BaseType);
}
то при вызове этого метода вы должны указать параметр типа.
static void Main(string[] args) {
…
// Если метод не имеет параметров,
// необходимо указать параметр типа.
DisplayBaseClass‹int›();
DisplayBaseClass‹string›();
// Ошибка компиляции!
// Нет параметров? Тогда должен быть заполнитель!
DisplayBaseClass();
…
}
Рис. 10.1. Обобщенные методы в действии
В данном случае обобщенные методы Swap‹T› и DisplayBaseClass‹T› были определены в рамках объекта приложения (т.е. в рамках типа, определяющего метод Main()). Если вы предпочтете определить эти члены в новом типе класса (MyHelperClass), то должны записать следующее.
public class MyHelperClass {
public static void Swap‹T›(ref T a, ref T b) {
Console.WriteLine("Методу Swap() передано {0}", typeof(T));
T temp;
temp = a;
a = b;
b = temp;
}
public static void DisplayBaseClass‹T›() {
Console.WriteLine("Базовым классом {0} является: {1}.", typeof(T), typeof(T).BaseType);
}
}