. Возникает законный вопрос: насколько полна предлагаемая система ограничений? Конечно, речь идет о практической полноте, а не о математически строгих определениях. С позиций практики систему хотелось бы дополнить, в первую очередь, введением ограничений операций, указывающим допустимые знаки операций в выражениях над объектами соответствующего типа. Хотелось бы, например, указать, что к объектам типа T применима операция сложения + или операция сравнения <. Позже я покажу, как можно справиться с этой проблемой, но предлагаемое решение довольно сложно. Наличие ограничения операций намного элегантнее решало бы эту проблему. Синтаксис ограничений Уточним некоторые синтаксические правила записи ограничений. Если задан универсальный класс с типовыми параметрами T1, ... Tn, то на каждый параметр могут быть наложены ограничения всех типов. Ограничения задаются предложением where, начинающимся соответствующим ключевым словом, после которого следует имя параметра, а затем через двоеточие - ограничения первого, второго или третьего типа, разделенных запятыми. Порядок их важен: если присутствует ограничение третьего типа, то оно записывается первым. Заметьте, предложения where для разных параметров отделяются лишь пробелами; как правило, они записываются на отдельных строчках. Предложения where записываются в конце заголовка класса после имени и списка его типовых параметров, после родительских классов и интерфейсов, если они заданы для универсального класса. Вот синтаксически корректные объявления классов с ограничением универсальности: public class Father<T1, T2> { } public class Base { public void M1() { } public void M2() { } } public class Child<T1,T2> :Father<T1,T2> where T1:Base,IEnumerable<T1>, new() where T2:struct,IComparable<T2> { } Класс Child с ограниченной универсальностью к данным типа T1 имеет право применять методы M1 и M2 базового класса Base; так же, как и методы интерфейса IEnumerable<T1>, он может создавать объекты типа T1, используя конструктор по умолчанию. Фактический тип, подставляемый вместо формального типа T2, должен быть значимым, и объекты этого типа разрешается сравнивать между собой. Список с возможностью поиска элементов по ключу Ключевые идеи ограниченной универсальности, надеюсь, понятны. Давайте теперь рассмотрим пример построения подобного класса, где можно будет увидеть все детали. Возьмем классическую и саму по себе интересную задачу построения списка с курсором. Как и всякий контейнер данных, список следует сделать универсальным, допускающим хранение данных разного типа. С другой стороны, мы не хотим, чтобы в одном списке происходило смешение типов, - уж если там хранятся персоны, то чисел int |