Чтение онлайн

на главную

Жанры

Полное руководство. С# 4.0
Шрифт:

Обобщения как языковое средство очень важны потому, что они позволяют создавать классы, структуры, интерфей сы, методы и делегаты для обработки разнотипных данных с соблюдением типовой безопасности. Как вам должно быть известно, многие алгоритмы очень похожи по своей логике независимо от типа данных, к которым они приме няются. Например, механизм, поддерживающий очередь, остается одинаковым независимо от того, предназначена ли очередь для хранения элементов типа int, string, object или для класса, определяемого пользователем. До появле ния обобщений для обработки данных разных типов при ходилось создавать различные варианты одного и того же алгоритма. А благодаря обобщениям можно сначала вы работать единое решение независимо от конкретного типа данных, а затем применить

его к обработке данных самых разных типов без каких-либо дополнительных усилий.

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

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

Следует особо подчеркнуть, что в C# всегда имелась возможность создавать обоб щенный код, оперируя ссылками типа object. А поскольку класс object является базовым для всех остальных классов, то по ссылке типа object можно обращаться к объекту любого типа. Таким образом, до появления обобщений для оперирования разнотипными объектами в программах служил обобщенный код, в котором для этой цели использовались ссылки типа object.

Но дело в том, что в таком коде трудно было соблюсти типовую безопасность, по скольку для преобразования типа object в конкретный тип данных требовалось при ведение типов. А это служило потенциальным источником ошибок из-за того, что приведение типов могло быть неумышленно выполнено неверно. Это затруднение по зволяют преодолеть обобщения, обеспечивая типовую безопасность, которой раньше так недоставало. Кроме того, обобщения упрощают весь процесс, поскольку исключа ют необходимость выполнять приведение типов для преобразования объекта или дру гого типа обрабатываемых данных. Таким образом, обобщения расширяют возможно сти повторного использования кода и позволяют делать это надежно и просто.

ПРИМЕЧАНИЕ Программирующим на C++ и Java необходимо иметь в виду, что обобщения в C# не сле дует путать с шаблонами в C++ и обобщениями в Java, поскольку это разные, хотя и похожие средства. В действительности между этими тремя подходами к реализации обобщений суще ствуют коренные различия. Если вы имеете некоторый опыт программирования на C++ или Java, то постарайтесь на основании этого опыта не делать никаких далеко идущих выводов о том, как обобщения действуют в С#. Простой пример обобщений

Начнем рассмотрение обобщений с простого примера обобщенного класса. В при веденной ниже программе определяются два класса. Первым из них является обобщен ный класс Gen, вторым — класс GenericsDemo, в котором используется класс Gen. // Простой пример обобщенного класса. using System; // В приведенном ниже классе Gen параметр типа Т заменяется // реальным типом данных при создании объекта типа Gen. class Gen<T> { Т ob; // объявить переменную типа Т // Обратите внимание на то, что у этого конструктора имеется параметр типа Т. public Gen(T о) { ob = о; } // Возвратить переменную экземпляра ob, которая относится к типу Т. public Т GetOb { return ob; } // Показать тип Т. public void ShowType { Console.WriteLine("К типу T относится " + typeof(Т)); } } // Продемонстрировать применение обобщенного класса. class GenericsDemo { static void Main { // Создать переменную ссылки на объект Gen типа int. Gen<int> iOb; // Создать объект типа Gen<int> и присвоить ссылку на него переменной iOb. iOb = new Gen<int>(102); // Показать тип данных, хранящихся в переменной iOb. iOb.ShowType; // Получить значение переменной iOb. int v = iOb.GetOb; Console.WriteLine("Значение: " + v); Console.WriteLine; // Создать объект типа Gen для строк. Gen<string> strOb = new Gen<string>("Обобщения повышают эффективность."); // Показать тип данных, хранящихся в переменной strOb. strOb.ShowType; // Получить значение переменной strOb. string str = strOb.GetOb; Console.WriteLine("Значение: " + str); } }

Эта программа дает следующий результат. К типу Т относится System.Int32 Значение: 102 К типу Т относится System.String Значение: Обобщения повышают эффективность.

Внимательно проанализируем эту программу. Прежде всего обратите внимание на объявление класса Gen в приведенной ниже строке кода: class Gen<T> {

где Т — это имя параметра типа. Это имя служит в качестве метки-заполнителя кон кретного типа, который указывается при создании объекта класса Gen. Следовательно, имя Т используется в классе Gen всякий раз, когда требуется параметр типа. Обратите внимание на то, что имя Т заключается в угловые скобки (< >). Этот синтаксис мож но обобщить: всякий раз, когда объявляется параметр типа, он указывается в угловых скобках. А поскольку параметр типа используется в классе Gen, то такой класс счита ется обобщенным.

В объявлении класса Gen можно указывать любое имя параметра типа, но по тра диции выбирается имя Т. К числу других наиболее употребительных имен параметров типа относятся V и Е. Вы, конечно, вольны использовать и более описательные имена, например TValue или ТКеу. Но в этом случае первой в имени параметра типа при нято указывать прописную букву Т.

Далее имя Т используется для объявления переменной ob, как показано в следую щей строке кода. Т ob; // объявить переменную типа Т

Как пояснялось выше, имя параметра типа Т служит меткой-заполнителем кон кретного типа, указываемого при создании объекта класса Gen. Поэтому переменная ob будет иметь тип, привязываемый к Т при получении экземпляра объекта класса Gen. Так, если вместо Т указывается тип string, то в экземпляре данного объекта перемен ная оb будет иметь тип string.

А теперь рассмотрим конструктор класса Gen. public Gen(Т о) { ob = о; }

Как видите, параметр о этого конструктора относится к типу Т. Это означает, что конкретный тип параметра о определяется типом, привязываемым к Т при создании объекта класса Gen. А поскольку параметр о и переменная экземпляра ob относятся к типу Т, то после создания объекта класса Gen их конкретный тип окажется одним и тем же.

С помощью параметра типа Т можно также указывать тип, возвращаемый мето дом, как показано ниже на примере метода GetOb. public Т GetOb { return ob; }

Переменная ob также относится к типу Т, поэтому ее тип совпадает с типом, воз вращаемым методом GetOb.

Метод ShowType отображает тип параметра Т, передавая его оператору typeof. Но поскольку реальный тип подставляется вместо Т при создании объекта класса Gen, то оператор typeof получит необходимую информацию о конкретном типе. В классе GenericsDemo демонстрируется применение обобщенного класса Gen.

Сначала в нем создается вариант класса Gen для типа int. Gen<int> iOb;

Внимательно проанализируем это объявление. Прежде всего обратите внимание на то, что тип int указывается в угловых скобках после имени класса Gen. В этом случае int служит аргументом типа, привязанным к параметру типа Т в классе Gen. В данном объявлении создается вариант класса Gen, в котором тип Т заменяется типом int вез де, где он встречается. Следовательно, после этого объявления int становится типом переменной ob и возвращаемым типом метода GetOb.

В следующей строке кода переменной iOb присваивается ссылка на экземпляр объекта класса Gen для варианта типа int. iOb = new Gen<int>(102);

Поделиться:
Популярные книги

Горькие ягодки

Вайз Мариэлла
Любовные романы:
современные любовные романы
7.44
рейтинг книги
Горькие ягодки

Кодекс Охотника. Книга XXVI

Винокуров Юрий
26. Кодекс Охотника
Фантастика:
попаданцы
5.00
рейтинг книги
Кодекс Охотника. Книга XXVI

Девяностые приближаются

Иванов Дмитрий
3. Девяностые
Фантастика:
попаданцы
альтернативная история
7.33
рейтинг книги
Девяностые приближаются

Эффект Фостера

Аллен Селина
Любовные романы:
современные любовные романы
5.00
рейтинг книги
Эффект Фостера

Леди Малиновой пустоши

Шах Ольга
Любовные романы:
любовно-фантастические романы
6.20
рейтинг книги
Леди Малиновой пустоши

Убийца

Бубела Олег Николаевич
3. Совсем не герой
Фантастика:
фэнтези
попаданцы
9.26
рейтинг книги
Убийца

Попутчики

Страйк Кира
Любовные романы:
любовно-фантастические романы
5.00
рейтинг книги
Попутчики

Последняя Арена 11

Греков Сергей
11. Последняя Арена
Фантастика:
фэнтези
боевая фантастика
рпг
5.00
рейтинг книги
Последняя Арена 11

На границе империй. Том 9. Часть 5

INDIGO
18. Фортуна дама переменчивая
Фантастика:
космическая фантастика
попаданцы
5.00
рейтинг книги
На границе империй. Том 9. Часть 5

Последний Паладин. Том 6

Саваровский Роман
6. Путь Паладина
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Последний Паладин. Том 6

Измена. Не прощу

Леманн Анастасия
1. Измены
Любовные романы:
современные любовные романы
4.00
рейтинг книги
Измена. Не прощу

Польская партия

Ланцов Михаил Алексеевич
3. Фрунзе
Фантастика:
попаданцы
альтернативная история
5.25
рейтинг книги
Польская партия

Ох уж этот Мин Джин Хо – 3

Кронос Александр
3. Мин Джин Хо
Фантастика:
попаданцы
5.00
рейтинг книги
Ох уж этот Мин Джин Хо – 3

Третий. Том 2

INDIGO
2. Отпуск
Фантастика:
космическая фантастика
попаданцы
5.00
рейтинг книги
Третий. Том 2