Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
lab_13_14 / ЛАБ_14_C# / Лаб1.doc
Скачиваний:
10
Добавлен:
02.02.2015
Размер:
268.8 Кб
Скачать

Лаб.раб №14

Делегаты и события

Содержание

1 Делегаты …………………………………………………………… 2

1.1 Ссылка делегата на статические методы …………………… 2

№ 1…………………………………………………………. 2

1.2 Ссылка делегата на методы экземпляров класса…………… 4

№ 2………………………………………………………….. 4

1.3 Многоадресная арифметика…………………………………. 6

№ 3…………………………………………………………. 6

2 События……………………………………………………………. 7

2.1 Пример применения постейшего события………………….. 8

№ 4…………………………………………………………. 8

    1. Работа с событием для многоадресной передачи………….. 9

№ 5………………………………………………………….. 9

    1. Методы экземпляров класса как обработчики событий…… 10

№ 6………………………………………………………….. 10

№ 7…………………………………………………………. 11

    1. Использование событийных средств доступа……………… 12

№ 8………………………………………………………….. 12

2.5 Особенности обработки событий в среде .NET Framework.. 14

№ 9………………………………………………………….. 14

    1. Применение всироенного делегата EventHandler………….. 15

№ 10………………………………………………………… 15

    1. Пример создания разработчика событий нажатия клавиш… 16

№ 11 ………………………………………………………. 16

1 Делегаты

Делегат – это объект, который может ссылаться на метод в процессе выполнения программы. Делегат может вызывать метод, на который он ссылается. Делегат объявляется с помощью ключевого слова delegate. Общая фома объявления следующая:

delegate тип_возврата имя_делегата(список_параметров);

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

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

1.1 Ссылка делегата на статические методы

1

// Первая простая пограмма с делегатом

using System;

// Объявление делегата

delegate string strMod(string str);

class DelegateTest

{

// Метод замеяет пробелы дефисами.

static string replaceSpaces(string a)

{

Console.WriteLine("\n Замена пробелов дефисами.");

return a.Replace(' ', '-');

}

// Метод удаляет побелы.

static string removeSpaces(string a) {

string temp = "";

int i;

Console.WriteLine(" Удаление пробелов.");

for (i = 0; i < a.Length; i++)

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

return temp;

}

// Метод реверсирует строку

static string reverse(string a) {

string temp = "";

int i,j;

Console.WriteLine(" Реверсирование строки.");

for(j=0, i=a.Length-1; i >= 0; i--,j++)

temp += a[i];

return temp;

}

public static void Main()

{

// Создание делегата.

strMod strOp = new strMod(replaceSpaces);

string str;

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

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

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

Console.WriteLine();

strOp = new strMod(removeSpaces);

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

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

Console.WriteLine();

strOp = new strMod(reverse);

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

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

Console.WriteLine("\n\n\n ");

}

}

Рис 1 Результаты работы первой программы с делегатами

Отметим ряд особнностей работы с делегатом

1 В программе делегату дано имя strMod (имя выбирается программистом). Это имя используется как имя метода, который получает один параметр типа string и возвращает одно значение типа string-значения.

2 В функции Main() составляется основное уравнение, связывающее имя делегата strMod с созданием ссылки c именем strOp на метод, выполняющем требуемое преобразование, поручаемое делегату. Представим это уравнение таким образом:

(имя делегата) (имя ссылки) = new (имя делегата) (имя метода преобразования);

D reference = new D (reform());

Мы получили классическую в С# зависимость между ссылкой и методом, выполняющим требуемое преобразование.

  1. Структура метода reform() имеет такой вид

// комментарий о конкретном выполняемом преобразовании

static string reform (string a) {

string temp = f(a) ;

return temp ;

}

4 f(a) – способ формирования (создания) выходного string-значения. Это может быть один из известных методов класса string (в рассмотренном выше примере это метод Replace() - a.Replace(‘ ‘, ‘-‘); ) или отдельные решения, отвечающие поставленным требованиям (в рассмотренной задаче – это string temp = a[i];).

5 Создается впечатление, что одно имя делегата может быть использовано для множества преобразований.

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

delegate тип_возврата имя(список_параметров);

7 Делегат может вызвать только такие методы, у которых тип возврощаемого значения и список параметров (т.е. его сигнатура) совпадают с соответствующими элементами объявления делегата.

8 Делегат может ссылаться на методы экземпляров класса, но при этом он должен использовать объктную ссылку.

Ниже приводится текст предыдущей программы, переписанный с целью инкапсуляци операций над строками внутри класса StringOps.

1.2 Ссылка делегата на экземпляры класса

2 - предыдущая программа, но делегаты ссылаются на методы экземпляров класса.

// Делегаты ссылаются на методы экземпляров кдасса

using System;

// Объявление делегата

delegate string strMod(string str);

class StringOps

{

// Метод замеяет пробелы дефисами.

public string replaceSpaces(string a)

{

Console.WriteLine("\n Замена пробелов дефисами.");

return a.Replace(' ', '-');

}

// Метод удаляет пробелы.

public string removeSpaces(string a)

{

string temp = "";

int i;

Console.WriteLine(" Удаление пробелов.");

for (i = 0; i < a.Length; i++)

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

return temp;

}

// Метод реверсирует строку

public string reverse(string a)

{

string temp = "";

int i, j;

Console.WriteLine(" Реверсирование строки.");

for (j = 0, i = a.Length - 1; i >= 0; i--, j++)

temp += a[i];

return temp;

}

}

class DelegateTest {

public static void Main()

{

// Создается экземпляр класса StringOps.

StringOps so = new StringOps();

// Создаем делегат.

strMod strOp = new strMod( so.replaceSpaces );

string str;

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

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

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

Console.WriteLine();

strOp = new strMod( so.removeSpaces );

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

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

Console.WriteLine();

strOp = new strMod( so.reverse );

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

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

Console.WriteLine("\n\n\n ");

}

}

Рис 2 Повторение результатов задачи № 1

1.3 Многоадресатная передача

Особенность делегата – поддержка многоадресатной передачи (multicasting). Многоадресатная пердача – это способность создавать список вызовов (или цепочку вызовов) методов, которые должны автоматически вызываться при вызове делегата. Для создания такой цепочки достаточно создать экземпляр делегата, а затем для добавления методов в эту цепочку использовать операто «+=». Для удаления метода из цепочки используется оператор «-=» .

№ 3

// Применение многоадресатной пердачи

using System;

// Объявляем делегат.

delegate void strMod(ref string str);

class StringOps

{

// Метод заменяет пробелы дефисами.

static void replaceSpaces(ref string a)

{

Console.WriteLine("\n Замена пробелов дефисами.");

a = a.Replace(' ', '-');

}

//Метод удаляет пробелы.

static void removeSpaces(ref string a)

{

string temp = "";

int i;

Console.WriteLine(" Удаление пробелов.");

for (i = 0; i < a.Length; i++)

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

a = temp;

}

// Метод реверсирует строку.

static void reverse(ref string a) {

string temp = "";

int i, j;

Console.WriteLine(" Реверсирование строки.");

for(j =0, i=a.Length -1; i >= 0; i--, j++)

temp += a[i];

a = temp;

}

public static void Main() {

// Создаем экземпляры делегатов.

strMod strOp;

strMod replaceSp = new strMod(replaceSpaces);

strMod removeSp = new strMod(removeSpaces);

strMod reverseStr = new strMod(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("\n\n\n ");

}

}

Рис 3 Результат применения многоадресатной пердачи

Основные выводы о важности применения делегатов:

1 Делегаты обеспечивают поддержку функционирования событий.

2 Делегаты позволяют во время выполнения программы выполнить метод, который точно не известен в период компляции. Это особенно полезно для подключения программных компонент к создаваемым оболочкам.