"Разборчивые" события
"Разборчивые" события
Есть еще одно усовершенствование, которое можно внести в наш пример с CarEvents и которое соответствует шаблону событий, рекомендуемому разработчиками из Microsoft. При исследовании событий, посылаемых данным типом из библиотек базовых классов, вы обнаружите, что первым параметром соответствующего делегата является System.Object, а вторым – тип, производный от System.EventArgs.
Аргумент System.Object представляет ссылку на объект, посылающий событие (такой как, например, Car), а второй параметр представляет информацию о соответствующем событии. Базовый класс System.EventArgs представляет событие и не передает никакой пользовательской информации.
public class EventArgs {
public static readonly System.EventArgs Empty;
public EventArgs();
}
Для простых событий вы можете просто передать экземпляр EventArgs. Но если вы хотите передать и пользовательские данные, вы должны построить подходящий класс, производный от EventArgs. Для нашего примера мы предположим, что у нас есть класс CarEventArgs, который содержит строку с сообщением, отправляемым получателю.
public class CarEventArgs: EventArgs {
public readonly string msg;
public CarEventArgs(string message) {
msg = message;
}
}
Теперь мы должны обновить делегат CarEventHandler так, как показано ниже (события должны остаться без изменений).
public class Car {
public delegate void CarEventHandler(object sender, CarEventArgs e);
…
}
При генерировании событий из метода Accelerate() мы теперь должны предоставить ссылку на текущий объект Car (с помощью ключевого слова Car) и экземпляр нашего типа CarEventArgs.
public void Accelerate(int delta) {
// Если машина сломалась, генерируется событие Exploded.
if (carIsDead) {
if (Exploded != null) Exploded(this, new CarEventArgs("Извините, машина сломалась…"));
else {
…
AboutToBlow(this, new CarEventArgs("Осторожно! Могу сломаться!"));
}
…
}
}
С точки зрения вызывающей стороны, все, что нам требуется, так это обновление обработчиков событий, чтобы иметь возможность принять поступающие параметры и получить сообщение через доступное только для чтения поле. Например:
public static void CarAboutToBlow(object sender, CarEventArgs e) { Console.WriteLine ("{0} сообщает: {1}", sender, e.msg); }
Если получатель желает взаимодействовать с объектом, отправившим событие, следует выполнить явное преобразование System.Object. Так, если нужно выключить радио, когда объект Car уже на полпути к своему создателю, можно предложить обработчик событий, который будет выглядеть примерно так.
public static void CarIsAlmostDoomed(object sender, CarEventArgs e) {
// Просто для гарантии здесь перед вызовом предлагается
// проверка среды выполнения.
if (sender is Car) {
Car с = (Car)sender;
c.CrankTunes(false);
}
Console.WriteLine("Важное сообщение от {0}: {1}", sender, e.msg);
}
Исходный код. Проект PrimAndProperCarEvenfs размещен в подкаталоге, соответствующем главе 8.