Вы добавляете ограничение путем указания интерфейса I P r i o r i t i z a b l e в заголовке P r i o r i t y Q u e u e :
c l a s s P r i o r i t y Q u e u e < T > where T: IPrioritizable
Обратите внимание на выделенную полужирным шрифтом конструкцию, начинаю щуюся со слова w h e r e . Это принудителъ (enforcer), который указывает, что тип Т обя зан реализовывать интерфейс I P r i o r i t i z a b l e , т.е. как бы говорит компилятору: "Убедись, подставляя конкретный тип вместо Т, что он реализует интерфейс I P r i o r i tizable, а иначе просто сообщи об ошибке".
Вы указываете ограничения, перечисляя в конструкции w h e r e одно или не сколько имен:
имя базового класса, от которого должен быть порожден класс Т (или должен быть этим классом);
имя интерфейса, который должен быть реализован классом Т, как было показано в предыдущем примере.
Дополнительные варианты ограничений включают ключевые слова s t r u c t , c l a s s inew(). С new () вы встретитесь чуть позже в этой главе, а об ограничениях s t r u c t и class можно прочесть в разделе "Generics, constraints" справочной системы.
Эти варианты ограничений повышают гибкость в описании поведения обобщенного иасса. Вот пример гипотетического обобщенного класса, объявленного с несколькими ограничениями на Т:
class MyClass<T> : w h e r e Т: c l a s s , I P r i o r i t i z a b l e , new ()
}
Здесь тип T должен быть классом, а не типом-значением; он должен реализовать интерфейс I P r i o r i t i z a b l e и содержать конструктор без параметров. Достаточно
А если у вас есть два обобщенных параметра и оба должны иметь ограниче ния? (Да, да — вы можете использовать несколько обобщенных параметров одновременно!) Вот как можно записать две конструкции w h e r e :
c l a s s MyClass<T, U> : w h e r e T: I P r i o r i t i z a b l e , w h e r e U: new()
Определение значения null д л я типа T
Как уже упоминалось ранее, у каждого типа есть свое значение по умолчанию, озна
чающее "ничто" для данного типа. Для |
i n t |
и других типов чисел это 0 (или 0.0). Для |
string— пустая строка " " . Для b o o l |
это |
f a l s e , а для всех ссылочных типов, таких |
как Package, это n u l l . |
|
|
Однако поскольку обобщенный класс |
наподобие P r i o r i t y Q u e u e может быть ин- |
панцирован практически для любого типа данных, С# не в состоянии предсказать, каким должно быть правильное значение n u l l в исходном тексте обобщенного класса. Напри мер, в методе Dequeue () класса P r i o r i t y Q u e u e вы можете оказаться именно в такой ситуации: вы вызываете Dequeu e ( ) , но очередь пуста и пакетов нет. Что вы должны вер нуть, что бы могло означать "ничего"? Поскольку P a c k a g e — класс, следует вернуть зна чение n u l l . Это сообщит вызывающей функции, что ничего вернуть не удалось (вызывающая функция, само собой, должна проверять, не вернулось ли значение n u l l ) .