Ограничение обобщения Описание
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() {…}

// MyGenericClass получается из МуВаsе и реализует ISomeInterface,

// а вложенные элементы должны быть структурами.

public class MyGenericClass‹T›: MyBase, ISomeInterface where T: struct {…}

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

// ‹К› должен иметь конструктор, заданный по умолчанию,

// а ‹Т› должен реализовывать открытый интерфейс IComparable.

public class MyGenericClass‹K, T› where K: new() where T: IComparable‹T› {…}

Если вы хотите изменить тип CarCollection‹T› так, чтобы в него можно было поместить только производные от Car, вы можете записать следующее.

public' class CarCollection‹T›: IEnumerable‹T› where T: Car {

 public void PrintPetName(int роs) {

  // Поскольку теперь все элементы должны быть из семейства Car,

  // свойство PetName можно вызывать непосредственно.

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

 }

}

При таких ограничениях на CarCollection‹T› реализация PrintPetName() становится очень простой, поскольку теперь компилятор может предполагать, что ‹Т› является производным от Car. Более того, если указанный пользователем параметр типа не совместим с Car, будет сгенерирована ошибка компиляции.

// Ошибка компиляции!

CarCollection‹int› myInts = new CarCollection‹int›();

Вы должны понимать, что обобщенные методы тоже могут использовать ключевое слово where. Например, если нужно гарантировать, чтобы методу Swap(), созданному в этой главе выше, передавались только типы, производные от System. ValueType, измените свой программный код так.

// Этот метод переставит любые типы, характеризуемые значениями.

static void Swap‹T›(ref Т а, ref T b) where T: struct {

 …

}

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

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