
- •Введение
- •Сравнение языков С++ и C#
- •Логические выражения
- •Функции для ввода и вывода в языке C#
- •Управление форматом числовых данных:
- •Обработка исключительных ситуаций
- •Методы и модификаторы параметров
- •Неявно типизированные переменные
- •Понятие класса
- •Свойства
- •Индексаторы
- •Одномерные индексаторы
- •Многомерные индексаторы
- •Перегрузка методов
- •Перегрузка знаков операций
- •Наследование
- •Виртуальные функции
- •Работа с файлами
- •Работа с каталогами
- •Абстрактный класс FileSystemInfo
- •Класс DirectoryInfo
- •Сериализация
- •FileSystemWatcher – отслеживание событий, связанных с файлами
- •Обобщения (шаблоны)
- •Интерфейсы
- •Коллекции
- •LINQ
- •Грамматика выражений запросов
- •Синтаксис запросов
- •Проекция и фильтрация
- •Упорядочение
- •Агрегирующие запросы
- •Операции с коллекциями
- •Операция Concat
- •Операция Union
- •Преобразование
- •Объединение последовательностей
- •FirstOrDefault
- •Группировка
- •Групповая адресация
- •Обработка событий
- •Групповое преобразование делегируемых методов
- •Применение методов экземпляра в качестве делегатов
- •Групповая адресация
- •Ковариантность и контравариантность
- •Класс System. Delegate
- •Назначение делегатов
- •Анонимные функции
- •Анонимные методы
- •Передача аргументов анонимному методу
- •Возврат значения из анонимного метода
- •Применение внешних переменных в анонимных методах
- •Лямбда-выражения
- •Лямбда-оператор
- •Одиночные лямбда-выражения
- •Блочные лямбда-выражения
- •События
- •Пример групповой адресации события
- •Применение аксессоров событий
- •Разнообразные возможности событий
- •Применение анонимных методов и лямбда-выражений вместе с событиями
- •Рекомендации по обработке событий в среде .NET Framework
- •Применение делегатов EventHandler<TEventArgs> и EventHandler
- •Практический пример обработки событий
Чернов Э. А. |
- 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();
}
}
}
Выполнение этого кода приводит к следующему результату.
Замена пробелов дефисами.
Обращение строки.