Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лекции по ООП (язык C#).pdf
Скачиваний:
190
Добавлен:
16.05.2015
Размер:
1.54 Mб
Скачать

Чернов Э. А.

- 127 -

Лекции по языку C# v 2.3

метод RemoveSpaces (), и с его помощью вновь вызывается указанный метод - на этот раз RemoveSpaces (). И наконец, экземпляру делегата strOp присваивается ссылка на метод Reverse (). А в итоге вызывается именно этот метод. Главный вывод из данного примера заключается в следующем: в тот момент, когда происходит обращение к экземпляру делегата strOp, вызывается метод, на который он ссылается. Следовательно, вызов метода разрешается во время выполнения, а не в процессе компиляции.

Групповое преобразование делегируемых методов

Еще в версии С# 2.0 было внедрено специальное средство, существенно упрощающее синтаксис присваивания метода делегату. Это так называемое групповое преобразование методов, позволяющее присвоить имя метода делегату, не прибегая к оператору new или явному вызову конструктора делегата.

Ниже приведен метод Main () из предыдущего примера, измененный с целью демонстрации группового преобразования методов.

static void Main()

{

//Сконструировать делегат, используя групповое преобразование методов.

StrMod strOp = ReplaceSpaces; // использовать групповое преобразование методов

string str;

//Вызвать методы с помощью делегата.

str = str0p(“Этo простой тест.");

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

strOp=RemoveSpaces;//использовать групповое преобразование методов str = str0p(“Этo простой тест.");

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

Console.WriteLine() ;

strOp -= Reverse; // использовать групповое преобразование методов str = str0p(“Этo простой тест.");

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

Console.WriteLine();

}

Обратите особое внимание на то, как создается экземпляр делегата strOp и как ему присваивается метод ReplaceSpaces в следующей строке кода.

strOp=RemoveSpaces;//использовать групповое преобразование методов

В этой строке кода имя метода присваивается непосредственно экземпляру делегата strOp, а все заботы по автоматическому преобразованию метода в тип делегата "возлагаются" на средства С#. Этот синтаксис может быть распространен на любую ситуацию, в которой метод присваивается или преобразуется в тип делегата. Синтаксис группового преобразования методов существенно упрощен по сравнению с прежним подходом к делегированию, поэтому в остальной части книги используется именно он.

Применение методов экземпляра в качестве делегатов

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

Чернов Э. А.

- 128 -

Лекции по языку C# v 2.3

случае может быть также использован синтаксис группового преобразования методов.

using System;

using System.Collections.Generic; using System.Linq;

using System.Text;

namespace ConsoleApplication1

{

class Program

{

//Делегаты могут ссылаться и на методы экземпляра.

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

delegate string StrMod(string str); class StringOps

{

//Заменить пробелы дефисами. public string ReplaceSpaces(string s)

{

Console.WriteLine("Замена пробелов дефисами."); return s.Replace(' ', '-');

}

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

public string RemoveSpaces (string s)

{

string temp = ""; int i;

Console.WriteLine("Удаление пробелов."); for(i=0; i < s.Length; i++)

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

}

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

public string Reverse(string s)

{

string temp = ""; int i, j;

Console.WriteLine("Обращение строки."); for(j=0, i=s.Length-1; i >= 0; i--, j++)

temp += s[i]; return temp;

}

}

class DelegateTest

{

static void Main()

{

StringOps so = new StringOps(); // создать экземпляр

//объекта класса StringOps

//Инициализировать делегат. StrMod strOp = so.ReplaceSpaces; string str;

//Вызвать методы с помощью делегатов.

Чернов Э. А. - 129 - Лекции по языку C# v 2.3

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

Console.WriteLine();

strOp = so.RemoveSpaces;

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

strOp = so.Reverse;

str = strOp("Это простой тест.");

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

}

}

}

}

Результат выполнения этого кода получается таким же, как и в предыдущем примере, но на этот раз делегат обращается к методам по ссылке на экземпляр объекта класса StringOps.

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

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

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

using System;

using System.Collections.Generic; using System.Linq;

using System.Text;

namespace DelegateTest2

{

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

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

delegate void StrMod(ref string str); class MultiCastDemo

{

// Заменить пробелы дефисами. static void ReplaceSpaces(ref string s)

{

Console.WriteLine("Замена пробелов дефисами."); s = s.Replace(' ', '-');

Чернов Э. А.

- 130 -

Лекции по языку C# v 2.3

}

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

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();

Console.ReadKey();

}

}

}

Выполнение этого кода приводит к следующему результату.

Замена пробелов дефисами.

Обращение строки.