Читайте также: |
|
Обобщения позволяют создавать классы, структуры, интерфейсы, методы и делегаты для обработки разнотипных данных с соблюдением типовой безопасности. Многие алгоритмы очень похожи по своей логике независимо от типа данных, к которым они применяются.
Например, механизм, поддерживающий очередь, остается одинаковым независимо от того, предназначена ли очередь для хранения элементов типа int, string, object или для класса, определяемого пользователем. До появления обобщений для обработки данных разных типов приходилось создавать различные варианты одного и того же алгоритма.
А благодаря обобщениям можно сначала выработать единое решение независимо от конкретного типа данных, а затем применить его к обработке данных самых разных типов без каких-либо дополнительных усилий.
Термин обобщение, по существу, означает параметризированный тип. Особая роль параметризированных типов состоит в том, что они позволяют создавать классы, структуры, интерфейсы, методы и делегаты, в которых обрабатываемые данные указываются в виде параметра.
С помощью обобщений можно, например, создать единый класс, который автоматически становится пригодным для обработки разнотипных данных.
Класс, структура, интерфейс, метод или делегат, оперирующий параметризированным типом данных, называется обобщенным ( например, обобщенный класс или обобщенный метод).
В С# всегда имелась возможность создавать обобщенный код, оперируя ссылками типа object. А поскольку класс object является базовым для всех остальных классов, то по ссылке типа object можно обращаться к объекту любого типа. Таким образом, до появления обобщений для оперирования разнотипными объектами в программах служил обобщенный код, в котором для этой цели использовались ссылки типа object.
Но дело в том, что в таком коде трудно было соблюсти типовую безопасность, поскольку для преобразования типа object в конкретный тип данных требовалось приведение типов. А это служило потенциальным источником ошибок из-за того, что приведение типов могло быть неумышленно выполнено неверно.
Обобщения, обеспечивают типовую безопасность и упрощают весь процесс, поскольку исключают необходимость выполнять приведение типов для преобразования объекта или другого типа обрабатываемых данных.
Таким образом, обобщения расширяют возможности повторного использования кода и позволяют делать это надежно и просто.
Пример обобщенного класса.
В программе определяются два класса: обобщенный класс Gen, класс GenericsDemo, в котором используется класс Gen.
using System;
//В классе Gen параметр типа Т заменяется
// реальным типом данных при создании объекта типа Gen.
class Gen<T>
{ Т ob; // объявить переменную типа Т
public Gen(T о) // у этого конструктора имеется параметр типа Т.
{ ob = o;}
// Возвратить переменную экземпляра ob, которая относится к типу Т.
public T GetOb()
{return ob;}
// Показать тип Т.
public void ShowType()
{Console.WriteLine("К типу Т относится " + typeof(T)); }
}
class GenericsDemo {
static void Main() {
// Создать переменную ссылки на объект Gen типа int.
Gen<int> iOb;
// Создать объект типа Gen<int> и присвоить ссылку на него переменной iOb.
iOb = new Gen<int>(2);
// Показать тип данных, хранящихся в переменной 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 всякий раз, когда требуется параметр типа. Имя Т заключается в угловые скобки (< >).
Когда объявляется параметр типа, он указывается в угловых скобках.
В объявлении класса можно указывать любое имя параметра типа, но по традиции выбирается имя Т. К числу других наиболее употребительных имен параметров типа относятся V и Е. Возможно использовать и более описательные имена, например TValue или ТКеу. Но в этом случае первой в имени параметра типа принято указывать прописную букву Т.
Далее имя Т используется для объявления переменной ob:
Т ob; // объявить переменную типа Т
имя параметра типа Т служит меткой-заполнителем конкретного типа, указываемого при создании объекта класса Gen. Поэтому переменная ob будет иметь тип, привязываемый к Т при получении экземпляра объекта класса Gen.
Так, если вместо Т указывается тип string, то в экземпляре данного объекта переменная ob будет иметь тип string.
В конструкторе класса Gen.
public Gen(T о) {ob = о;}
параметр о относится к типу Т. Это означает, что конкретный тип параметра о определяется типом, привязываемым к Т при создании объекта класса Gen. А поскольку параметр о и переменная экземпляра ob относятся к типу Т, то после создания объекта класса Gen их конкретный тип окажется одним и тем же.
С помощью параметра типа Т можно также указывать тип, возвращаемый методом:
public T 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>(2);
при вызове конструктора класса Gen указывается также аргумент типа int. Это необходимо потому, что переменная (в данном случае — iOb), которой присваивается ссылка, относится к типу Gen<int>. Поэтому ссылка, возвращаемая оператором new, также должна относиться к типу Gen<int>. В противном случае во время компиляции возникнет ошибка.
Например, приведенное ниже присваивание станет причиной ошибки во время компиляции.
iOb = new Gen<double>A(8.12); // Ошибка!
Переменная iOb относится к типу Gen<int> и поэтому не может использоваться для ссылки на объект типа Gen<double>.
Такой контроль типов относится к одним из главных преимуществ обобщений, поскольку он обеспечивает типовую безопасность.
Затем в программе отображается тип переменной ob в объекте iOb — тип System.Int32. Это структура.NET, соответствующая типу int. Далее значение переменной ob получается в следующей строке кода.
int v = iOb.GetOb();
Возвращаемым для метода GetOb() является тип Т, который был заменен на тип int при объявлении переменной iOb, и поэтому метод GetOb() возвращает значение того же типа int. Следовательно, данное значение может быть присвоено переменной v как int.
Далее в классе GenericsDemo объявляется объект типа Gen<string>.
Gen<string> strOb = new Gen<string>("Обобщения повышают эффективность.");
В этом объявлении указывается аргумент типа string, поэтому в объекте класса Gen вместо Т подставляется тип string. Создается вариант класса Gen для типа string.
В классе обобщенного типа можно указать два или более параметра типа. В этом случае параметры типа указываются списком через запятую.
В качестве примера ниже приведен класс TwoGen, являющийся вариантом класса Gen с двумя параметрами типа.
// Простой обобщенный класс с двумя параметрами типа Т и V.
using System;
class TwoGen<T, V> {
T obi;
V ob2;
// В этом конструкторе указываются параметры типа Т и V.
public TwoGen(T ol, V о2) {
obi = ol;
оb2 = о2;
}
// Показать типы Т и V.
public void showTypes() {
Console.WriteLine("К типу Т относится " + typeof(T));
Console.WriteLine("К типу V относится " + typeof(V));
}
public T getobl() {
return obi;
}
public V Get0bj2() {
return ob2;
}
}
// Применение обобщенного класса с двумя параметрами типа,
class SimpGen {
static void Main() {
TwoGen<int, string> tgObj =
new TwoGen<int, string>(119, "Альфа Бета Гамма");
// Показать типы.
tgObj.showTypes();
// Получить и вывести значения,
int v = tgObj.getobl();
Console.WriteLine("Значение: " + v);
string str = tgObj.GetObj2();
Console.WriteLine("Значение: " + str);
}
}
Эта программа дает следующий результат.
К типу Т относится System.Int32
К типу V относится System.String
Значение: 119
Значение: Альфа Бета Гамма
Дата добавления: 2015-09-02; просмотров: 39 | Нарушение авторских прав
<== предыдущая страница | | | следующая страница ==> |
Русь изначальная. Зачем европейцы врут? | | | Глава Первая |