KnigaRead.com/
KnigaRead.com » Разная литература » Прочее » Герберт Шилдт - C# 4.0 полное руководство - 2011

Герберт Шилдт - C# 4.0 полное руководство - 2011

На нашем сайте KnigaRead.com Вы можете абсолютно бесплатно читать книгу онлайн "Герберт Шилдт - C# 4.0 полное руководство - 2011". Жанр: Прочее издательство неизвестно, год неизвестен.
Перейти на страницу:

ПРИМЕЧАНИЕ

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

Простой пример обобщений

Начнем рассмотрение обобщений с простого примера обобщенного класса. В приведенной ниже программе определяются два класса. Первым из них является обобщенный класс Gen, вторым — класс Generics Demo, в котором используется класс Gen.

// Простой пример обобщенного класса, using System;

//В приведенном ниже классе Gen параметр типа Т заменяется // реальным типом данных при создании объекта типа Gen. class Gen<T> {

Т ob; // объявить переменную типа Т

// Обратите внимание на то, что у этого конструктора имеется параметр типа public Gen(T о) { ob = о;

}

// Возвратить переменную экземпляра ob, которая относится к типу Т. public Т GetObO { return ob;

}

// Показать тип Т. public void ShowTypeO {

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, то в экземпляре данного объекта переменная ob будет иметь тип string.

А теперь рассмотрим конструктор класса Gen.

public Gen(T о) { ob = о;

}

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

С помощью параметра типа Т можно также указывать тип, возвращаемый методом, как показано ниже на примере метода GetOb ().

public Т GetOb()    {

return ob;

}

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

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

В классе Generics Demo демонстрируется применение обобщенного класса Gen. Сначала в нем создается вариант класса Gen для типа int.

Gen<int> iOb;

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

В следующей строке кода переменной iOb присваивается ссылка на экземпляр объекта класса Gen для варианта типа int.

iOb = new Gen<int> (102);

Обратите внимание на то, что при вызове конструктора класса Gen указывается также аргумент типа int. Это необходимо потому, что переменная (в данном случае — iOb), которой присваивается ссылка, относится к типу Gen<int>. Поэтому ссылка, возвращаемая оператором new, также должна относиться к типу Gen<int>. В противном случае во время компиляции возникнет ошибка. Например, приведенное ниже присваивание станет причиной ошибки во время компиляции.

iOb = new Gen<double>(118.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, как демонстрируют остальные строки кода рассматриваемой здесь программы.

Перейти на страницу:
Прокомментировать
Подтвердите что вы не робот:*