// Дополнительные методы для MiniVan.

}

В соответствии с законами наследования, в коллекцию CarCollection‹T›, созданную с параметром типа Car, можно добавлять и типы MiniVan и SportsCar.

// CarCollection‹Car› может хранить любой тип, производный от Car.

CarCollection‹Car› myCars = new CarCollection‹Car›;

myInts.AddCar(new MiniVan("Family Truckster", 55);

myInts.AddCar(new SportsCar("Crusher", 40));

Это синтаксически корректно, но что делать, если вдруг понадобится добавить в CarCollection‹T› новый открытый метод, например, с именем PrintPetName? Такая задача кажется простой – достаточно получить доступ к подходящему элементу из List‹T› и вызвать свойство PetName.

// Ошибка!

// System.Объект не имеет свойства о именем PetName.

public void PrintPetName(int pos) {

 Console.WriteLine(arCars[pos].PetName);

}

Однако в таком виде программный код скомпилирован не будет, поскольку истинная суть ‹Т› еще не известна, и вы не можете с уверенностью утверждать, что какой-то элемент типа List‹T› будет иметь свойство PetName. Когда параметр типа не имеет никаких ограничений (как в данном случае), обобщенный тип называется свободным (unbound). По идее параметры свободного типа должны иметь только члены System.Object (которые, очевидно, не имеют свойства PetName).

Вы можете попытаться "обмануть" компилятор путем преобразования элемента, возвращенного из Метода индексатора List‹T›, в строго типизованный объект Car, чтобы затем вызвать petName возвращенного объекта.

// Ошибка!

// Нельзя превратить тип 'Т' в 'Car'!

public void PrintPetName(int pos) {

 Console.WriteLine(((Car)arCars[pos]).PetName);

}

Но это тоже не компилируется, поскольку компилятор не знает значения параметра типа ‹Т› и не может гарантировать, что преобразование будет законным.

Для решения именно таких проблем обобщения .NET могут опционально определяться с ограничениями, для чего используется ключевое слово where. В .NET 2.0 обобщения могут иметь ограничения, описанные в табл. 10.2.

Таблица 10.2. Возможные ограничения обобщений для параметров типа

Ограничение обобщения Описание
where T: struct Параметр типа ‹T› должен иметь в цепочке наследования System.ValueType
where T: class Параметр типа ‹T› не должен иметь в цепочке наследования System.ValueType (т.е. ‹Т› должен быть ссылочным типом)
where T: new Параметр типа ‹T› должен иметь конструктор, заданный по умолчанию. Это полезно тогда, когда обобщенный тип должен создать экземпляр параметра типа, а вы не имеете ясных предположений о формате пользовательских конструкторов. Заметьте, что это ограничение должно быть последним в списке ограничений, если у типа их несколько
where T: БазовыйКласс Параметр типа ‹T› должен быть производным класса, указанного параметром БазовыйКласс
where T: Интерфейс Параметр типа ‹T› должен реализовывать интерфейс, указанный параметром Интерфейс 

При наложении ограничений с помощью ключевого слова where список ограничений размещается после имени базового класса обобщенного типа и списка интерфейсов. В качестве конкретных примеров рассмотрите следующие ограничения обобщенного класса MyGenericClass.

// Вложенные элементы должны иметь конструктор,

// заданный по умолчанию.

public class MyGenericClass‹T› where T: new {…}

// Вложенные элементы должны быть классами, реализующими IDrawable

// и поддерживающими конструктор, заданный по умолчанию.

public class MyGenericClass‹T› where T: class, IDrawable, new {…}

Перейти на страницу:

Похожие книги