|
Программирование >> Программирование с использованием ajax
Здесь необходимо переименовать тип Т либо в методе, либо в классе. Ограничения могут использоваться параметрами обобщенного метода тем же образом, что и в классе, и применять в таком случае можно любые параметры типа класса: public class Defaulter<Tl> { public Т2 GetDefault<T2>О where Т2 : TI return default(T2); Здесь тип Т2, предоставляемый методу, должен обязательно либо совпадать, либо наследоваться от типа Т1, предоставляемого классу. Такой прием является наиболее типичным способом установки ограничений на обобщенные методы. Таким образом, получается, что в класс Farm<T>, который демонстрировался ранее, можно включить следующий метод (который присутствует в загружаемом коде для Chl2Ex04, но в закомментированном виде): public Farm<U> GetSpecies<U> () where U : T { Farm<U> speciesFarm = new Farm<U>(); foreach (T animal in animals) if (animal is U) { speciesFarm.Animals.Add(animal as U) ; return speciesFarm; Это приведет к замене метода GetCows () и любых других методов такого же типа. На используемый здесь параметр обобщенного типа - U - накладывает ограничения параметр Т, на который, в свою очередь накладывает ограничения класс Farm<T>, который разрешает использовать для него только тип Animal. Это открывает возможность воспринимать экземпляры Т как экземпляры Animal, если в том вдруг возникнет необходимость. Применение такового нового метода требует внесения в содержащийся в Program. cs клиентский код для Chl2Ex04 одного изменения: Farm<Cow> dairyFarm = farm.GetSpecies<Cow>(); Точно также можно написать и следующее: Farm<Chicken> dairyFarm = farm.GetSpecies<Chicken>() ; или использовать любой другой класс, унаследованный от Animal. Здесь важно обратить внимание на то, что наличие параметров обобщенного типа в методе приводит к изменению его сигнатуры. Это означает, что может существовать и несколько перегрузок метода, отличающихся друг от друга только параметрами обобщенного типа, как показано в следующем примере: public void ProcessT<T> (Т opl) { public void ProcessT<T, U>(T opl) To, какой из методов должен использоваться, будет определять количество указываемых при вызове метода параметров обобщенного типа. Определение обобщенных делегатов Последним обобщенным типом, который осталось рассмотреть, является обобщенный делегат. Как обобщенные делегаты выглядят в действии, уже показывалось ранее в этой главе при рассмотрении способов сортировки и поиска в обобщенных списках, где для того и другого применялись, соответственно, делегаты Comparison<T> и Predicate<T>. В главе 7 рассказывалось, что делегаты определяются путем указания параметров и возвращаемого типа метода, а также ключевого слова delegate и имени делегата: public delegate int MyDelegate(int opl, int op2); Обобщенные делегаты определяются объявлением и использованием одного или более параметров обобщенного типа: public delegate Tl MyDelegate<Tl, Т2>(Т2 opl, Т2 op2) where Tl : T2; Здесь видно, что ограничения могут накладываться и в случае обобщенных делегатов тоже и требуют соблюдения всех тех же правил. Более подробно о делегатах будет рассказываться в следующей главе, где помимо прочего еще будет демонстрироваться и то, как их можно использовать в таком распространенном в программировании на С# механизме, как события. Резюме В настоящей главе было показано, как использовать обобщенные типы в С# и каким образом создавать свои собственные обобщенные типы - обобщенные классы, интерфейсы, методы и делегаты. Здесь также было продемонстрировано и то, как использовать структуры, включая создание нулевых типов и работу с классами из пространства имен System.Collecitons.Generic. Обобщения, как можно было увидеть в этой главе, являются чрезвычайно мощным новым механизмом в С#. С их помощью можно создавать классы, способные служить сразу нескольким целям и подходящие для применения сразу в целом ряде разнообразных ситуаций. Даже если создавать свои собственные обобщенные типы нет причин, использовать обобщенные классы коллекций наверняка доведется постоянно. В следующей главе мы продолжим изучение базовых аспектов языка С#, а именно - уточним некоторые детали и рассмотрим события. Упражнения 1. Какие из следующих элементов могут быть обобщенными? Классы Методы Свойства Перегруженные версии операций Структуры Перечисления 2. Расширьте класс Vector в СЫ2Ех01 так, чтобы операция * возвращала скалярное произведение двух векторов. Под скалярным произведением двух векторов понимается результат перемножения их модулей, помноженный на косинус угла между ними. 3. Что не так в следующем коде? Исправьте ошибку. public class Instantiator<T> { public Т instance; public Instantiator0 { instance = new T () ; 4. Что не так в следующем коде? Исправьте ошибку. public class StringGetter<T> { public string GetString<T> (T item) { return item.ToString0; 5. Создайте обобщенный класс по имени ShortCollection<T>, реализующий IList<T> и состоящий из коллекции элементов с максимальным размером. Этот максимальный размер должен иметь вид целого числа, которое могло бы предоставляться конструктору ShortCollection<T> или по умолчанию устанавливаться в 10. Конструктор должен также быть способным принимать первоначальный список элементов через параметр List<T>. Сам класс должен функционировать точно так же, как Collection<T>, но генерировать исключение типа IndexOutOfRangeException при попытке добавить в коллекцию слишком много элементов или при наличии слишком большого количества элементов в переданном конструктору списке List<T>.
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |