000140. Делегаты и события в c#

Делегаты и события в c#||wmysterio|wmysterio|wmysterio@yandex.ru|||Всем хай! Прошло очень много времени прежде, чем я понял как работают события и как их вызывать. Пришло время передать мой опыт вам! Начнём с ознакомлением нового слова - delegate. Делегат - это объект, который может ссылаться на метод. Его также можно назвать "прототипом метода". Объявляется он как обычный метод, только с приставкой изучаемого нами слова:

СПЕЦИФИКАТОР delegate ТИП ИМЯ ( СПИСОК_ПАРАМЕТРОВ );

Так, как делегат - это прототип метода, то он содержит: - тип возвращаемого значения. Обычно его ставят на void, делая из метода процедуру. - имя процедуры или метода - список параметров, которые передаются в метод. Если их нет, то оставляют пустые скобки. Делегат можно объявлять как в пространстве имён, так и внутри класса. В качестве примера создадим делегат внутри класса Car, с которым мы игрались в предыдущих уроках:

public delegate void CarEvent();

Я назвал более понятным языком, что бы вам было легче понять. Наш делегат называется "Событие автомобиля". Мы не указываем какое именно, а только общее для всех. В нём не будет параметров. Событие - это реакция на какое-то действие с объектом. Чтобы объявить событие, достаточно написать следующий код:

public event CarEvent Wrecked;

Мы указали видимость этого события, казали ключевое слово event и прототип метода(наш делегат) и имя события. Наш класс теперь такой:

public class Car { public delegate void CarEvent(); public event CarEvent Wrecked; public Car() { Name = "Автомобиль"; } public string Name { get; set; } public int CurrentSpeed { get; set; } }

private int _health; public int Health { get { return _health; } set { _health = value; if ( 1 > _health && Wrecked != null ) Wrecked(); } }

Думаю, вы обратили внимание на блок set, а именно на проверку. Расскажу для чего она нужно. Чтобы событие отвечало действительности, нам нужно проверить, что бы жизнь транспорта был меньше нуля а также проверить на то, что событие существует и не вызвано. Теперь изюминка: откуда взялся метод Wrecked()? Я бы назвал его гибридом, так как имя метода формируется из события, а параметры - из делегата, причём параметр делегата называют аргументом, а все аргументы - сигнатурой. Вызывая этот метод мы сообщаем о том, что событие произошло. Теперь наш класс имеет такой вид:

public class Car { public delegate void CarEvent(); public event CarEvent Wrecked; public Car() { Name = "Автомобиль"; Health = 100; } public string Name { get; set; } public int CurrentSpeed { get; set; } private int _health; public int Health { get { return _health; } set { _health = value; if ( 1 > _health && Wrecked != null ) Wrecked(); } } }

Теперь если указать значение жизни транспорта ниже 1 произойдёт событие Wrecked. Наша задача выполнена - мы написали своё событие в c# без использования стандартных конструкций. Мы можем подписаться и отписываться на события. Для этого служат следующие выражения:

+=

Оформить подписку на событие

-=

Отписаться от события

Вот пример подписки на события:

Car MyCar = new Gallardo(); MyCar.Wrecked += new Car.CarEvent( MyCar_Wrecked );

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

static void MyCar_Wrecked() { Console.WriteLine("Транспорт уничтожен!"); }

for ( int i = 50; i > -5; i-- ) { Console.WriteLine("Жизнь транспорта: {0}", i); MyCar.Health = i; }

MyCar.Wrecked -= new Car.CarEvent( MyCar_Wrecked );

Полностью идентичен записи подписки, только со знаком -. Когда использовать это выражение? Давайте напишем код так, чтобы обработчик сообщил только 1 раз, что транспорт уничтожен. так как поля и методы у "главного класса" статические, то объявим переменную DisableEvent типа bool, которая будет сообщать когда отписаться от события:

class Program { static bool DisableEvent = false; static void Main() { Car MyCar = new Gallardo(); MyCar.Wrecked += new Car.CarEvent( MyCar_Wrecked ); for ( int i = 50; i > -5; i-- ) { Console.WriteLine("Жизнь транспорта: {0}", i); MyCar.Health = i; if ( DisableEvent ) MyCar.Wrecked -= new Car.CarEvent( MyCar_Wrecked ); } Console.ReadKey(); } public static void MyCar_Wrecked() { Console.WriteLine("Транспорт уничтожен!"); DisableEvent = true; } }

object sender, EventArgs e

Объясню что это такое и откуда оно берётся: object sender - это объект класса который передал событие. EventArgs e - аргументы, которые были указаны в делегате; указывается класс конструктор которого является делегатом. Возвращает публичные поля этого класса. Принято аргументы называть буквой e, (от event) Давайте модифицируем делегат с этого примера:

public delegate void CarEvent( object sender, int e);

Также нам нужно отредактировать вызов события под эту сигнатуру:

if ( 1 > _health && Wrecked != null ) Wrecked(this, _health);

this - указываем объект, который передаёт событие, в нашим случаи передастся Car. В качестве аргумента e передаём поле класса - _health. Теперь переработаем обработчик под сигнатуру:

public static void MyCar_Wrecked( object sender, int e ) { Console.WriteLine("Транспорт уничтожен!"); DisableEvent = true; }

Last updated