- Фантастика и фэнтези
- Ироническое фэнтези
- Стимпанк
- Детективная фантастика
- Киберпанк
- Попаданцы
- LitRPG
- Космоопера
- Технофэнтези
- Городская фантастика
- Русское фэнтези
- Юмористическая фантастика
- Космическая фантастика
- Боевое фэнтези
- Эпическая фантастика
- Зарубежная фантастика
- Книги магов
- Мистика
- Разная фантастика
- Разное фэнтези
- Любовное фэнтези
- Романтическая фантастика
- Городское фентези
- Историческая фантастика
- Историческое фэнтези
- Социально-философская фантастика
- Сказочная фантастика
- Иностранное фэнтези
- Романтическое фэнтези
- Ироническая фантастика
- Ужасы и Мистика
- Постапокалипсис
- Героическая фантастика
- Фэнтези
- Научная Фантастика
- Социально-психологическая
- Альтернативная история
- Боевая фантастика
- Разная литература
- Пословицы, поговорки
- Шахматы
- Визуальные искусства
- Фанфик
- Авто и ПДД
- Военное
- Отраслевые издания
- Гиды, путеводители
- Зарубежная образовательная литература
- Военная история
- Цитаты из афоризмов
- Современная литература
- Великолепные истории
- Начинающие авторы
- Современная зарубежная литература
- Боевые искусства
- Изобразительное искусство, фотография
- Кино
- Литература 19 века
- Недвижимость
- Музыка, музыканты
- Готические новеллы
- Истории из жизни
- Культура и искусство
- Спецслужбы
- Зарубежная прикладная литература
- Музыка, танцы
- Подростковая литература
- Прочее
- Военная техника, оружие
- Газеты и журналы
- Периодические издания
- Домоводство, Дом и семья
- Любовные романы
- Экономическая литература
- Научные и научно-популярные книги
- О животных
- Биохимия
- Культурология
- Юриспруденция
- Политика
- Психотерапия
- Языкознание
- Научпоп
- Медицина
- Психология, личное
- Радиотехника
- Филология
- Педагогика
- Образовательная литература
- Деловая литература
- Физика
- Науки: разное
- Химия
- Воспитание детей, педагогика
- Детская психология
- Зарубежная публицистика
- Биология
- Архитектура
- Зарубежная психология
- Науки о космосе
- Социология
- Математика
- География
- Беременность, ожидание детей
- Литературоведение
- Транспорт, военная техника
- Обществознание
- Зоология
- География
- Альтернативная медицина
- Иностранные языки
- Ветеринария
- Рефераты
- Астрология
- Биофизика
- Экология
- История Европы
- Учебники
- Шпаргалки
- Государство и право
- Ботаника
- Религиоведение
- История
- Техническая литература
- Прочая научная литература
- Психология
- Детективы и Триллеры
- Справочная литература
- Проза
- Новелла
- Юмор
- Проза
- Историческая проза
- Русская современная проза
- Советская классическая проза
- Повести
- Очерки
- Эссе
- Рассказы
- Зарубежная современная проза
- Сентиментальная проза
- Зарубежная классика
- Афоризмы
- Эпистолярная проза
- Феерия
- Семейный роман/Семейная сага
- Разное
- Антисоветская литература
- Магический реализм
- Русская классическая проза
- Современная проза
- О войне
- Контркультура
- Классическая проза
- Поэзия, Драматургия
- Детская литература
- Детская фантастика
- Детские остросюжетные
- Детские стихи
- Детские приключения
- Внеклассное чтение
- Учебная литература
- Зарубежные детские книги
- Бизнес
- Загадки
- Книги для подростков
- Школьные учебники
- Детский фольклор
- Книги для дошкольников
- Детские детективы
- Детская познавательная и развивающая литература
- Буквари
- Прочая детская литература
- Сказка
- Детская проза
- Детская образовательная литература
- Юмор
- Документальные книги
- Бизнес
- Внешнеэкономическая деятельность
- Тайм-менеджмент
- Кадровый менеджмент
- О бизнесе популярно
- Управление, подбор персонала
- Бизнес
- Менеджмент и кадры
- Продажи
- Экономика
- Ценные бумаги и инвестиции
- Малый бизнес
- Делопроизводство, офис
- Корпоративная культура, бизнес
- Банковское дело
- Финансы
- Зарубежная деловая литература
- Ораторское искусство / риторика
- Личные финансы
- Интернет-бизнес
- Поиск работы
- Государственное и муниципальное управление
- Бухучет и аудит
- Работа с клиентами
- Менеджмент
- Краткое содержание
- Личная эффективность
- Переговоры
- Приключения
- Старинная литература
- Религия и духовность
- Компьютеры и Интернет
- Блог
Читаем без скачивания ЯЗЫК ПРОГРАММИРОВАНИЯ С# 2005 И ПЛАТФОРМА .NET 2.0. 3-е издание - Эндрю Троелсен
Шрифт:
Интервал:
Закладка:
}
}
При таких ограничениях на 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 {
…
}
Следует также понимать то, что при таком ограничении метод Swap() уже не сможет переставлять строковые типы (поскольку они являются ссылочными).
Отсутствие поддержки ограничений при использовании операций
При создании обобщенных методов для вас может оказаться сюрпризом появление ошибок компилятора, когда с параметрами типа используются операции C# (+, -, *, == и т.д.). Например, я уверен, вы сочли бы полезными классы Add(), Subtract(), Multiply() и Divide(), способные работать с обобщенными типами.
// Ошибка компиляции!
// Нельзя применять операции к параметрам типа!
public class BasicMath‹T› {
public T Add(T arg1, T arg2) { return arg1 + arg2; }
public T Subtract(T arg1, T arg2) { return arg1 – arg2; }
public T Multiply(T arg1, T arg2) { return arg1 * arg2; }
public T Divide(T arg1, T arg2) { return arg1 / arg2; }
}
Как ни печально, этот класс BasicMath‹T› не компилируется. Это может показаться большим ограничением, но не следует забывать, что обобщения являются обобщениями. Конечно, тип System.Int32 может прекрасно работать с бинарными операциями C#. Однако, если, например, ‹T› будет пользовательским классом иди типом структуры, компилятор не сможет сделать никаких предположений о характере перегруженных операций +, -, * и /. В идеале C# должен был бы позволять обобщенному типу ограничения с использованием операций, например, так.
// Только для иллюстрации!
// Этот программный код не является допустимым в C# 2.0.
public class BasicMath‹T› where T: operator +, operator -, operator *, operator / {
public T Add(T arg1, T arg2) { return arg1 + arg2; }
public T Subtract(T arg1, T arg2) { return arg1 – arg2; }
public T Multiply(T arg1, T arg2) { return arg1 * arg2; }
public T Divide(T arg1, T arg2) { return arg1 / arg2; }
}
Увы, ограничения обобщенных типов при использовании операций в C# 2005 не поддерживаются.
Исходный код. Проект CustomGenericCollection размещен в подкаталоге, соответствующем главе 10.
Создание обобщенных базовых классов
Перед рассмотрением обобщенных интерфейсов следует указать на то, что обобщенные классы могут быть базовыми для других классов и могут таким образом определять любое число виртуальных и абстрактных методов. Однако производные типы должны подчиняться определенным правилам, вытекающим из природы обобщенной абстракции. Во-первых, если обобщенный класс расширяется необобщенным, то производный класс должен конкретизировать параметр типа,
// Предположим, что создан пользовательский
// обобщенный класс списка.
public class MyList‹T› {
private List‹T› listOfData = new List‹T›();
}
// Конкретные типы должны указать параметр типа,
// если они получаются из обобщенного базового класса.
public class MyStringList: MyList‹string› {}
Кроме того, если обобщенный базовый класс определяет обобщенные виртуальные или абстрактные методы, производный тип должен переопределить эти обобщенные методы, используя конкретизированный параметр типа.
// Обобщенный класс с виртуальным методом.
public class MyList‹T› {
private List‹T› listOfData = new List‹T›();
public virtual void PrintList(T data) {}
}
public class MyStringList: MyList‹string› {
// В производных методах нужно заменить параметр типа,
// используемый а родительском классе.
public override void PrintList(string data) {}
}
Если производный тип тоже является обобщенным, дочерний класс может (опционально) использовать заменитель типа в своем определении. Однако знайте, что любые ограничения, размещенные в базовом классе, должны "учитываться" и производным типом. Например:
// Обратите внимание, теперь здесь имеется ограничение,
// требующее конструктор по умолчанию.
public class MyList‹T› where T: new() {
private List‹T› listOfData = new List‹T›();
public virtual void PrintList(T data) {}
// Производный тип должен учитывать ограничения базового.
public class MyReadOnlyList‹T›: MyList‹T› where T: new() {
public override void PrintList(T data) {}
}
Если вы только не планируете построить свою собственную библиотеку обобщений, вероятность того, что вам придется строить иерархии обобщенных классов, оказывается практически нулевой. Тем не менее, вы теперь знаете, что язык C# обеспечивает поддержку наследования обобщений.
Создание обобщенных интерфейсов
Вы уже видели при рассмотрении пространства имен System.Collections. Generiс, что обобщенные интерфейсы в C# также допустимы (например, IEnumerable‹Т›). Вы, конечно, можете определить свои собственные обобщенные интерфейсы (как с ограничениями, так и без ограничений). Предположим, что нужно определить интерфейс, который сможет выполнять бинарные операции с параметрами обобщенного типа.
public interface IBinaryOperations‹T› {
T Add(T arg1, T arg2);
T Subtract(T arg1, T arg2);
T Multiply(T arg1, T arg2);
T Divide(T arg1, T arg2);
}
Известно, что интерфейсы остаются почти бесполезными, пока они не реализованы некоторым классом или структурой. При реализации обобщенного интерфейса поддерживающий его тип указывает тип заполнителя.
public class BasicMath: IBinaryOperations‹int› {
public int Add(int arg1, int arg2) { return arg1 + arg2; }
public int Subtract(int arg1, int arg2) { return arg1 – arg2; }
public int Multiply(int arg1, int arg2) { return arg1 * arg2; }
public int Divide(int arg1, int arg2) { return arg1 / arg2; }
}
После этого вы можете использовать BasicMath, как и ожидали.
static void Main(string[] args) {
Console.WriteLine("***** Обобщенные интерфейсы *****n");
BasicMath m = new BasicMath();
Console.WriteLine("1 + 1 = {0}", m.Add(1, 1));
Console.ReadLine();
}
Если вместо этого требуется создать класс BasicMath, действующий на числа с плавающим десятичным разделителем, можно конкретизировать параметр типа так.
public class BasicMath: IBinaryOperations‹double› {
public double Add(double arg1, double arg2) { return arg1 + arg2; }
…
}
Исходный код. Проект GenericInterface размещен в подкаталоге, соответствующем главе 10.
Создание обобщенных делегатов
Наконец, что не менее важно, .NET 2.0 позволяет определять обобщенные типы делегата. Предположим, например, что требуется определить делегат, который сможет вызывать любой метод, возвращающий void и принимающий один аргумент. Если аргумент может меняться, это можно учесть с помощью параметра типа. Для примера рассмотрим следующий программный код (обратите внимание на то, что целевые объекты делегата регистрируются как с помощью "традиционного" синтаксиса делегата, так и с помощью группового преобразования метода).
namespace GenericDelegate {
// Этот обобщенный делегат может вызвать любой метод,
// возвращающий void и принимающий один параметр.
public delegate void MyGenericDelegate‹T›(T arg);
class Program {
static void Main(string[] args) {
Console.WriteLine("***** Обобщенные делегаты *****n");
// Регистрация цели с помощью 'традиционного'
// синтаксиса делегата.
MyGenericDelegate‹string› strTarget = new MyGenericDelegate‹string›(StringTarget);
strTarget("Некоторые строковые данные");
// Регистрация цели с помощью
// группового преобразования метода.
MyGenericDelegate‹int› intTarget = IntTarget;