Делегат объявляет сигнатуру функции, и когда она используется как событие в классе, она также действует как набор зачисленных целей вызова. Синтаксис + = и - = для события используется для добавления цели в список.
Учитывая следующие делегаты, используемые в качестве событий:
// arguments for events
public class ComputerEventArgs : EventArgs
{
public Computer Computer { get; set; }
}
public class ComputerErrorEventArgs : ComputerEventArgs
{
public Exception Error { get; set; }
}
// delegates for events
public delegate void ComputerEventHandler(object sender, ComputerEventArgs e);
public delegate void ComputerErrorEventHandler(object sender, ComputerErrorEventArgs e);
// component that raises events
public class Thing
{
public event ComputerEventHandler Started;
public event ComputerEventHandler Stopped;
public event ComputerEventHandler Reset;
public event ComputerErrorEventHandler Error;
}
Вы бы подписались на эти события со следующим:
class Program
{
static void Main(string[] args)
{
var thing = new Thing();
thing.Started += thing_Started;
}
static void thing_Started(object sender, ComputerEventArgs e)
{
throw new NotImplementedException();
}
}
Хотя аргументы могут быть любыми, объект-отправитель и EventArgs e - это соглашение, которое используется очень последовательно. + = Thing_started сначала создаст экземпляр делегата, указывающего на целевой метод, а затем добавит его к событию.
В самом компоненте вы обычно добавляете методы для запуска событий:
public class Thing
{
public event ComputerEventHandler Started;
public void OnStarted(Computer computer)
{
if (Started != null)
Started(this, new ComputerEventArgs {Computer = computer});
}
}
Вы должны проверить на нулевое значение, если к событию не было добавлено ни одного делегата. Однако при выполнении вызова метода будут вызваны все добавленные делегаты. Вот почему для событий тип возвращаемого значения void - единого возвращаемого значения нет - поэтому для передачи информации у вас будут свойства в EventArgs, которые обработчики событий будут изменять.
Еще одним уточнением было бы использование общего делегата EventHandler, а не объявление конкретного делегата для каждого типа аргументов.
public class Thing
{
public event EventHandler<ComputerEventArgs> Started;
public event EventHandler<ComputerEventArgs> Stopped;
public event EventHandler<ComputerEventArgs> Reset;
public event EventHandler<ComputerErrorEventArgs> Error;
}