
- •Введение
- •Сравнение языков С++ и C#
- •Логические выражения
- •Функции для ввода и вывода в языке C#
- •Управление форматом числовых данных:
- •Обработка исключительных ситуаций
- •Методы и модификаторы параметров
- •Неявно типизированные переменные
- •Понятие класса
- •Свойства
- •Индексаторы
- •Одномерные индексаторы
- •Многомерные индексаторы
- •Перегрузка методов
- •Перегрузка знаков операций
- •Наследование
- •Виртуальные функции
- •Работа с файлами
- •Работа с каталогами
- •Абстрактный класс FileSystemInfo
- •Класс DirectoryInfo
- •Сериализация
- •FileSystemWatcher – отслеживание событий, связанных с файлами
- •Обобщения (шаблоны)
- •Интерфейсы
- •Коллекции
- •LINQ
- •Грамматика выражений запросов
- •Синтаксис запросов
- •Проекция и фильтрация
- •Упорядочение
- •Агрегирующие запросы
- •Операции с коллекциями
- •Операция Concat
- •Операция Union
- •Преобразование
- •Объединение последовательностей
- •FirstOrDefault
- •Группировка
- •Групповая адресация
- •Обработка событий
- •Групповое преобразование делегируемых методов
- •Применение методов экземпляра в качестве делегатов
- •Групповая адресация
- •Ковариантность и контравариантность
- •Класс System. Delegate
- •Назначение делегатов
- •Анонимные функции
- •Анонимные методы
- •Передача аргументов анонимному методу
- •Возврат значения из анонимного метода
- •Применение внешних переменных в анонимных методах
- •Лямбда-выражения
- •Лямбда-оператор
- •Одиночные лямбда-выражения
- •Блочные лямбда-выражения
- •События
- •Пример групповой адресации события
- •Применение аксессоров событий
- •Разнообразные возможности событий
- •Применение анонимных методов и лямбда-выражений вместе с событиями
- •Рекомендации по обработке событий в среде .NET Framework
- •Применение делегатов EventHandler<TEventArgs> и EventHandler
- •Практический пример обработки событий
Чернов Э. А. |
- 141 - |
Лекции по языку C# v 2.3 |
раметров, их необходимо заключить в скобки. Ниже приведен пример использования лямбдавыражения с целью определить, находится ли значение в заданных пределах.
(low, high, val) => val >= low && val <= high;
А вот как объявляется тип делегата, совместимого с этим лямбда-выражением. delegate bool InRange(int lower, int upper, int v);
Следовательно, экземпляр делегата InRange может быть создан следующим образом.
InRange rangeOK = (low, high, val) => val >= low && val <= high;
После этого одиночное лямбда-выражение может быть выполнено так, как показано ниже.
if(rangeOK(l, 5, 3)) Console.WriteLine( "Число 3 находится в пределах от 1 до 5.");
И последнее замечание: внешние переменные могут использоваться и захватываться в лямбда-выражениях таким же образом, как и в анонимных методах.
Блочные лямбда-выражения
Как упоминалось выше, существуют две разновидности лямбда-выражений. Первая из них, одиночное лямбда-выражение, была рассмотрена в предыдущем разделе. Тело такого лямбда-выражения состоит только из одного выражения. Второй разновидностью является блочное лямбда-выражение. Для такого лямбдавыражения характерны расширенные возможности выполнения различных операций, поскольку в его теле допускается указывать несколько операторов. Например, в блочном лямбда-выражении можно использовать циклы и условные операторы if, объявлять переменные и т.д. Создать блочное лямбда-выражение нетрудно. Для этого достаточно заключить тело выражения в фигурные скобки. Помимо возможности использовать несколько операторов, в остальном блочное лямбдавыражение, практически ничем не отличается от только что рассмотренного одиночного лямбда-выражения.
Ниже приведен пример использования блочного лямбда-выражения для вычисления и возврата факториала целого значения.
//Применить два одиночных лямбда-выражения.
//Продемонстрировать применение блочного лямбда-выражения. using System;
//Делегат IntOp принимает один аргумент типа int
//и возвращает результат типа int.
delegate int IntOp(int end); class StatementLambdaDemo
{
static void Main()
{
//Блочное лямбда-выражение возвращает факториал
//передаваемого ему значения.
IntOp fact = n =>
{
int r = 1;
for (int i=l; i <= n; i++) r = i * r;
return r;
};
Чернов Э. А. |
- 142 - |
Лекции по языку C# v 2.3 |
Console.WriteLine("Факториал 3 равен " + factC)); Console.WriteLirie("Факториал 5 равен " + factE));
}
}
При выполнении этого кода получается следующий результат.
Факториал 3 равен б Факториал 5 равен 120
В приведенном выше примере обратите внимание на то, что в теле блочного лям- бда-выражения объявляется переменная г, организуется цикл for и используется оператор return. Все эти элементы вполне допустимы в блочном лямбдавыражении. И в этом отношении оно очень похоже на анонимный метод. Следовательно, многие анонимные методы могут быть преобразованы в блочные лямбдавыражения при обновлении унаследованного кода. И еще одно замечание: когда в блочном лямбдавыражении встречается оператор return, он просто обусловливает возврат из лямбдавыражения, но не возврат из охватывающего метода.
И в заключение рассмотрим еще один пример, демонстрирующий блочное лямбдавыражение в действии. Ниже приведен вариант первого примера из этой главы, измененного с целью использовать блочные лямбда-выражения вместо автономных методов для выполнения различных операций со строками.
//Первый пример применения делегатов, переделанный с
//целью использовать блочные лямбда-выражения.
//Объявить тип делегата,
delegate string StrMod(string s); class UseStatementLambdas
{
static void Main()
{
//Создать делегаты, ссылающиеся на лямбдавыражения,
//выполняющие различные операции с символьными строками.
//Заменить пробелы дефисами.
StrMod ReplaceSpaces = s =>
{
Console.WriteLine("Замена пробелов дефисами."); return s.Replace(' ', '-');
}; '
% // Удалить пробелы.
StrMod RemoveSpaces = s =>
{
string temp = ""; int i;
Console.WriteLine("Удаление пробелов."); for(i=0; i < s.Length; i++)
if (s[i] != ' ') temp += s[i] ; return temp;
}; // Обратить строку.
StrMod Reverse = s =>
{
string temp = ""; int i, j;
Console.WriteLine("Обращение строки.");
Чернов Э. А. |
- 143 - |
Лекции по языку C# v 2.3 |
for(j=0, i=s.Length-1; i >= 0; i--, j++) temp += s[i];
return temp;
};
string str;
// Обратиться к лямбда-выражениям с помощью делегатов. StrMod strOp = ReplaceSpaces;
str = strOp("Это простой тест."); Console.WriteLine("Результирующая строка: " + str);
Console.WriteLine() ; strOp = RemoveSpaces;
str = strOp("Это простой тест.");
Console.WriteLine("Результирующая строка: " + str); Console.WriteLine() ;
strOp = Reverse;
str = strOp("Это простой тест."); Console.WriteLine("Результирующая строка: " + str);
}
}
Результат выполнения кода этого примера оказывается таким же, как и в первом примере применения делегатов.
Замена пробелов дефисами.
Результирующая строка: Это-простой-тест.
Удаление пробелов.
Результирующая строка: Этопростойтест. Обращение строки.
Результирующая строка: .тсет йотсорп отЭ
События
Еще одним важным средством С#, основывающимся на делегатах, является событие. Событие, по существу, представляет собой автоматическое уведомление о том, что произошло некоторое действие. События действуют по следующему принципу: объект, проявляющий интерес к событию, регистрирует обработчик этого события. Когда же событие происходит, вызываются все зарегистрированные обработчики этого события. Обработчики событий обычно представлены делегатами.
События являются членами класса и объявляются с помощью ключевого слова event. Чаще всего для этой цели используется следующая форма:
event делегат_события имя_события;
где делегат_события обозначает имя делегата, используемого для поддержки события, а имя_события - конкретный объект объявляемого события.
Рассмотрим для начала очень простой пример.
//Очень простой пример, демонстрирующий событие. using System;
//Объявить тип делегата для события,
delegate void MyEventHandler();
// Объявить класс, содержащий событие, class MyEvent
{
public event MyEventHandler SomeEvent;
// Этот метод вызывается для запуска события, public void OnSomeEvent()
Чернов Э. А. |
- 144 - |
Лекции по языку C# v 2.3 |
{
if (SomeEvent != null)
SomeEvent();
}
}
class EventDemo
{
// Обработчик события, static void Handler()
{
Console.WriteLine("Произошло событие");
}
static void Main()
{
MyEvent evt = new MyEvent();
//Добавить метод Handler() в список событий, evt.SomeEvent += Handler;
//Запустить событие,
evt.OnSomeEvent(); Console.ReadKey();
}
}
Вот какой результат получается при выполнении этого кода.
Произошло событие
Несмотря на всю свою простоту, данный пример кода содержит все основные элементы, необходимые для обработки событий. Он начинается с объявления типа делегата для обработчика событий, как показано ниже.
delegate void MyEventHandler();
Все события активизируются с помощью делегатов. Поэтому тип делегата события определяет возвращаемый тип и сигнатуру для события. В данном случае параметры события отсутствуют, но их разрешается указывать.
Далее создается класс события MyEvent. В этом классе объявляется событие SomeEvent в следующей строке кода.
public event MyEventHandler SomeEvent;
Обратите внимание на синтаксис этого объявления. Ключевое слово event уведомляет компилятор о том, что объявляется событие.
Кроме того, в классе MyEvent объявляется метод OnSomeEvent (), вызываемый для сигнализации о запуске события. Это означает, что он вызывается, когда происходит событие. В методе OnSomeEvent () вызывается обработчик событий с помощью делегата SomeEvent.
if(SomeEvent != null) SomeEvent();
Как видите, обработчик вызывается лишь в том случае, если событие SomeEvent не является пустым. А поскольку интерес к событию должен быть зарегистрирован в других частях программы, чтобы получать уведомления о нем, то метод OnSomeEvent () может быть вызван до регистрации любого обработчика события. Но во избежание вызова по пустой ссылке делегат события должен быть проверен, чтобы убедиться в том, что он не является пустым.
В классе EventDemo создается обработчик событий Handler (). В данном простом примере обработчик событий просто выводит сообщение, но другие обработчики