Главная Случайная страница


Полезное:

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


Категории:

АрхитектураАстрономияБиологияГеографияГеологияИнформатикаИскусствоИсторияКулинарияКультураМаркетингМатематикаМедицинаМенеджментОхрана трудаПравоПроизводствоПсихологияРелигияСоциологияСпортТехникаФизикаФилософияХимияЭкологияЭкономикаЭлектроника






Групповая адресация





Одним из самых примечательных свойств делегата является поддержка групповой адресации. Попросту говоря, групповая адресация — это возможность создать список, или цепочку вызовов, для методов, которые вызываются автоматически при обращении к делегату. Создать такую цепочку нетрудно. Для этого достаточно получить экземпляр делегата, а затем добавить методы в цепочку с помощью оператора + или +=. Для удаления метода из цепочки служит оператор - или -=. Если делегат возвращает значение, то им становится значение, возвращаемое последним методом в списке вызовов. Поэтому делегат, в котором используется групповая адресация, обычно имеет возвращаемый тип void.

Ниже приведен пример групповой адресации. Это переработанный вариант предыдущих примеров, в котором тип значений, возвращаемых методами манипулирования строками, изменен на void, а для возврата измененной строки в вызывающую часть кода служит параметр типа ref. Благодаря этому методы оказываются более приспособленными для групповой адресации.

// Продемонстрировать групповую адресацию.

using System;

// Объявить тип делегата.

delegate void StrMod(ref string str);

class MultiCastDemo

{

// Заменить пробелы дефисами.

static void ReplaceSpaces(ref string s)

{

Console.WriteLine("Замена пробелов дефисами.");

s = s.Replace(' ', '-');

}

// Удалить пробелы.

static void RemoveSpaces(ref string s)

{

string temp = "";

int i;

Console.WriteLine("Удаление пробелов.");

for (i = 0; i < s.Length; i++)

if (s[i]!= ' ') temp += s[i];

s = temp;

}

// Обратить строку.

static void Reverse(ref string s)

{

string temp = "";

int i, j;

Console.WriteLine("Обращение строки");

for (j = 0, i = s.Length - 1; i >= 0; i--, j++)

temp += s[i];

s = temp;

}

static void Main()

{

//Сконструировать делегаты.

StrMod strOp;

StrMod replaceSp = ReplaceSpaces;

StrMod removeSp = RemoveSpaces;

StrMod reverseStr = Reverse;

string str = "Это простой тест.";

// Организовать групповую адресацию.

strOp = replaceSp;

strOp += reverseStr;

// Обратиться к делегату с групповой адресацией.

strOp(ref str);

Console.WriteLine("Результирующая строка: " + str);

Console.WriteLine();

// Удалить метод замены пробелов и добавить метод удаления пробелов.

strOp -= replaceSp;

strOp += removeSp;

str = "Это простой тест.";// восстановить исходную строку

// Обратиться к делегату с групповой адресацией.

strOp(ref str);

Console.WriteLine("Результирующая строка: " + str);

Console.WriteLine();

}

}

В методе Main() из рассматриваемого здесь примера кода создаются четыре экземпляра делегата. Первый из них, strOp, является пустым, а три остальных ссылаются на конкретные методы видоизменения строки. Затем организуется групповая адресация для вызова методов RemoveSpaces() и Reverse(). Это делается в приведенных ниже строках кода.

strOp = replaceSp;

strOp += reverseStr;

Сначала делегату strOp присваивается ссылка replaceSp, а затем с помощью оператора += добавляется ссылка reverseStr. При обращении к делегату strOp вызываются оба метода, заменяя пробелы дефисами и обращая строку, как и показывает приведенный выше результат.

Ковариантность и контравариантность

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

// Продемонстрировать ковариантность и контравариантность.

using System;

class X

{

public int Val;

}

// Класс Y, производный от класса X.

class Y: X { }

// Этот делегат возвращает объект класса X и

// принимает объект класса Y в качестве аргумента.

delegate X ChangeIt(Y obj);

class CocontraVariance

{

// Этот метод возвращает объект класса X и

// имеет объект класса X в качестве параметра.

static X IncrA(X obj)


{

X temp = new X();

temp.Val = obj.Val + 1;

return temp;

}

// Этот метод возвращает объект класса Y и

// имеет объект класса Y в качестве параметра.

static Y IncrB(Y obj)

{

Y temp = new Y();

temp.Val = obj.Val + 1;

return temp;

}

static void Main()

{

Y Yob = new Y();

// В данном случае параметром метода IncrA является объект класса X,

// а параметром делегата ChangeIt — объект класса Y. Но благодаря

// контравариантности следующая строка кода вполне допустима.

ChangeIt change = IncrA;

X Xob = change(Yob);

Console.WriteLine("Xob: " + Xob.Val);

// В этом случае возвращаемым типом метода IncrB служит объект класса Y,

// а возвращаемым типом делегата ChangeIt — объект класса X. Но благодаря

// ковариантности следующая строка кода оказывается вполне допустимой.

change = IncrB;

Yob = (Y)change(Yob);

Console.WriteLine("Yob: " + Yob.Val);

}

}

Xob: 1

Yob: 1

В данном примере класс Y является производным от класса X. А делегат ChangeIt объявляется следующим образом.

delegate X ChangeIt(Y obj);

Делегат возвращает объект класса X и принимает в качестве параметра объект класса Y. А методы IncrA() и IncrB() объявляются следующим образом.

static X IncrA(X obj)

static Y IncrB(Y obj)

Метод IncrA() принимает объект класса X в качестве параметра и возвращает объект того же класса. А метод IncrB() принимает в качестве параметра объект класса Y и возвращает объект того же класса. Но благодаря ковариантности и контравариантности любой из этих методов может быть передан делегату ChangeIt, что и демонстрирует рассматриваемый здесь пример. Таким образом, в строке

ChangeIt change = IncrA;

метод IncrA() может быть передан делегату благодаря контравариантности, так как объект класса X служит в качестве параметра метода IncrA(), а объект класса Y — в качестве параметра делегата ChangeIt. Но метод и делегат оказываются совместимыми в силу контравариантности, поскольку типом параметра метода, передаваемого делегату, служит класс, являющийся базовым для класса, указываемого в качестве типа параметра делегата.

Приведенная ниже строка кода также является вполне допустимой, но на этот раз благодаря ковариантности.

change = IncrB;

В данном случае возвращаемым типом для метода IncrB() служит класс Y, а для делегата — класс X. Но поскольку возвращаемый тип метода является производным классом от возвращаемого типа делегата, то оба оказываются совместимыми в силу ковариантности.







Date: 2015-09-02; view: 459; Нарушение авторских прав



mydocx.ru - 2015-2024 year. (0.01 sec.) Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав - Пожаловаться на публикацию