Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Руководство_по_C#.doc
Скачиваний:
0
Добавлен:
01.07.2025
Размер:
10.01 Mб
Скачать

11.8Средства обобщений Значения по умолчанию

При написании обобщенного кода иногда важно провести различие между типами значений и ссылочными типами. Такая потребность возникает, в частности, в том случае, если переменной параметра типа должно быть присвоено значение по умолчанию. Для ссылочных типов значением по умолчанию является null, для неструктурных типов значений — 0 или логическое значение false, если это тип bool, а для структур типа struct — объект соответствующей структуры с полями, установленными по умолчанию. В этой связи возникает вопрос: какое значение следует присваивать по умолчанию переменной параметра типа: null, 0 или нечто другое?

Например, если в следующем объявлении класса Test:

class Test<T> { Т obj ; // ...

переменной obj требуется присвоить значение по умолчанию, то какой из двух вариантов следует выбрать:

obj = null; // подходит только для ссылочных типов

obj =0; /* подходит только для числовых типов

перечислений, но не для структур */

Для разрешения этой дилеммы можно воспользоваться формой оператора default, приведенной ниже:

default(тип)

Эта форма оператора default пригодна для всех аргументов типа, будь то типы значений или ссылочные типы. Давайте рассмотрим пример:

using System;

namespace ConsoleApplication1

{

class ObEx<T>

{

public T obj = default(T); // Используем оператор default

}

class Program

{

static void Main()

{

ObEx<Program> a = new ObEx<Program>();

ObEx<int> b = new ObEx<int>();

if (a.obj == null)

Console.WriteLine("a.obj = null");

if (b.obj == 0)

Console.WriteLine("b.obj = 0");

Console.ReadKey();

}

}

}

Вывод программы:

a.obj = null

b.obj = 0

Кстати, работа программы не изменится, если не использовать default:

public T obj; (ОВН)

Статические члены

Статические члены обобщенных классов требуют особого внимания. Статические члены обобщенного класса разделяются только одним экземпляром класса. Рассмотрим пример, в котором класс StaticDemo<T> содержит статическое поле х:

public class StaticDemo<T>

{

public static int x;

}

Поскольку класс StaticDemo<T> используется как с типом string, так и с типом int, существуют два набора статических полей:

StaticDemo<string>.x = 4;

StaticDemo<int>.x = 5;

Console.WriteLine(StaticDemo<string>.x); // Выводит 4

11.9Обобщенные методы

В дополнение к обобщенным классам можно также определять обобщенные методы. В объявлении обобщенного метода присутствует обобщенный тип. Обобщенные методы могут быть определены внутри необобщенного класса.

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

Ниже приведена общая форма объявления обобщенного метода:

возвращаемый_тип имя_метода<список_параметров_типа>

(список_параметров)

{// ...

В любом случае список_параметров_типа обозначает разделяемый запятой список параметров типа. Обратите внимание на то, что в объявлении обобщенного метода список параметров типа следует после имени метода.

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

Давайте рассмотрим пример:

using System;

namespace ConsoleApplication1

{

// Создадим необобщенный класс

class InfoObject

{

// Обобщенный метод, использующий также ограничение

public static string Info<T>(T obj) where T : User

{ return obj.ToString(); }

}

class User

{

public User(string Name, int Age)

{

this.Name = Name;

this.Age = Age;

}

public string Name { get; set; }

public int Age { get; set; }

}

class UserPass : User

{

public UserPass(string Name, int Age, string Pass)

: base(Name, Age)

{ Password = Pass; }

public string Password { get; set; }

public override string ToString()

{

return String.Format("Информация о пользователе: Имя: {0} "+

"Возраст: {1} Пароль: {2}", Name, Age, Password);

}

}

class Program

{

static void Main()

{

UserPass user1 = new UserPass("Alex", 26, "12345");

// Вызываем обобщенный метод

string s = InfoObject.Info<UserPass>(user1);

Console.WriteLine(s);

Console.ReadKey();

}

}

}

Выполнение программы:

Информация о пользователе: Имя: Alex Возраст: 26 Пароль: 12345

Как видите, в данном примере используется обобщенный метод Info<T> выводящий информацию об объекте. При этом в данном методе используется ограничение на базовый класс User с помощью оператора where. В производном классе UserPass переопределяется метод ToString(), в результате чего, в консоли отображается информация о пользователе.