Сначала делегатуstrOpприсваивается ссылкаreplaceSp,а затем с помощью оператора += добавляется ссылкаreverseStr.При обращении к делегатуstrOpвызываются оба метода, заменяя пробелы дефисами и обращая строку, как и показывает приведенный выше результат.
Далее ссылкаreplaceSpудаляется из цепочки вызовов в следующей строке кода:
strOp -= replaceSp;
и добавляется ссылкаremoveSpв строке кода.
strOp += removeSp;
После этого вновь происходит обращение к делегату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,
// а параметром делегата Changelt — объект класса Y. Но благодаря // контравариантности следующая строка кода вполне допустима.
Changelt change = IncrA;
X Xob = change(Yob);