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

Чернов Э. А.

- 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 (). В данном простом примере обработчик событий просто выводит сообщение, но другие обработчики