Чтение онлайн

ЖАНРЫ

ЯЗЫК ПРОГРАММИРОВАНИЯ С# 2005 И ПЛАТФОРМА .NET 2.0. 3-е издание

Троелсен Эндрю

Шрифт:

 }

}

Конечно, когда вы создаете обобщенный List‹T›, нельзя сказать, что компилятор буквально создает совершенно новую реализацию типа List‹T›. Он обращается только к тем членам обобщенного типа, которые вы вызываете фактически. Чтобы пояснить это, предположим, что вы используете List‹T› для объектов SportsCar так.

static void Main(string[] args) {

 // Проверка List, содержащего объекты SportsCars.

 List‹SportsCar› myCars = new List‹SportsCar›;

 myCars.Add(new SportsCar);

 Console.WriteLine("Your List contains {0}", myCars.Count);

}

Если

с помощью ildasm.exe проверить генерируемый CIL-код, обнаружатся следующие подстановки.

.method private hidebysig static void Main(string[] args) cil managed {

 .entrypoint

 .maxstack 2

 .locals init ([0] class [mscorlib] System.Collections.Generic.'List`1'‹class SportsCar› myCars)

 newobj instance void class [mscorlib]System.Collections.Generic.'List`1'‹class SportsCar›::.ctor

 stloc.0

 ldloc.0

 newobj instance void CollectionGenerics.SportsCar::.ctor

 callvirt instance void class [mscorlib]System.Collections.Generic.'List`1'‹class SportsCar›::Add(!0)

 nop

 ldstr "Your List contains {0} item(s)."

 ldloc.0

 callvirt instance int32 class [mscorlib] System.Collections.Generic.'List`1' ‹class SportsCar›::get_Count

 box [mscorlib] System.Int32

 call void [mscorlib]System.Console::WriteLine(string, object)

 nop

 ret

}

Теперь, после изучения процесса использования обобщенных типов из библиотек базовых классов, в оставшейся части главы мы рассмотрим вопросы создания обобщенных методов, типов и коллекций.

Создание обобщенных методов

Чтобы научиться интегрировать обобщения в проекты, мы начнем с простого примера обычной подпрограммы свопинга. Целью этого примера является построение метода обмена, который сможет работать 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), то должны записать следующее.

Поделиться с друзьями: