logo search
C#, 320 стр

Класс с универсальными методами

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

class Change

{

static public void Swap<T>(ref T x1, ref T x2)

{

T temp;

temp = x1; x1 = x2; x2 = temp;

}

}

Как видите, сам класс в данном случае не имеет родовых параметров, но зато универсальным является статический метод класса swap, имеющий родовой параметр типа T. Этому типу принадлежат аргументы метода и локальная переменная temp. Всякий раз при вызове метода ему, наряду с фактическими аргументами, будет передаваться и фактический тип, заменяющий тип T в описании метода. О некоторых деталях технологии подстановки и выполнения метода поговорим в конце лекции, сейчас же лишь отмечу, что реализация вызова универсального метода в C# не приводит к существенным накладным расходам.

Рассмотрим тестирующую процедуру из традиционного для наших примеров класса Testing, в которой интенсивно используется вызов метода swap для различных типов переменных:

public void TestSwap()

{

int x1 = 5, x2 = 7;

Console.WriteLine("до обмена: x1={0}, x2={1}",x1, x2);

Change.Swap<int>(ref x1, ref x2);

Console.WriteLine("после обмена: x1={0}, x2={1}", x1, x2);

string s1 = "Савл", s2 = "Павел";

Console.WriteLine("до обмена: s1={0}, s2={1}", s1, s2);

Change.Swap<string>(ref s1, ref s2);

Console.WriteLine("после обмена: s1={0}, s2={1}", s1, s2);

Person pers1 = new Person("Савлов", 25, 1500);

Person pers2 = new Person("Павлов", 35, 2100);

Console.WriteLine("до обмена: ");

pers1.PrintPerson(); pers2.PrintPerson();

Change.Swap<Person>(ref pers1, ref pers2);

Console.WriteLine("после обмена:");

pers1.PrintPerson(); pers2.PrintPerson();

}

Обратите внимание на строки, осуществляющие вызов метода:

Change.Swap<int>(ref x1, ref x2);

Change.Swap<string>(ref s1, ref s2);

Change.Swap<Person>(ref pers1, ref pers2);

В момент вызова метода передаются фактические аргументы и фактические типы. В данном примере в качестве фактических типов использовались встроенные типы int и string и тип Person, определенный пользователем. Общая ситуация такова: если в классе объявлен универсальный метод со списком параметров M<T1, ...Tn> (...), то метод вызывается следующим образом: M<TYPE1, ... TYPEn>(...), где TYPEi - это конкретные типы.

Еще раз напомню, что все эти примеры построены в Whidbey, и вот как выглядят внешний вид среды разработки и окно с результаты работы этой процедуры.

Рис. 22.1.  Результаты работы универсальной процедуры swap

В этом примере использовался класс Person, и поскольку он появится и в следующих примерах, то приведу его текст:

class Person

{

public Person(string name, int age, double salary)

{

this.name = name; this.age = age; this.salary = salary;

}

public string name;

public int age;

public double salary;

public void PrintPerson()

{

Console.WriteLine("name= {0}, age = {1}, salary ={2}",

name, age, salary);

}

}