Обработка событий с помощью методов расширения C#
недавно я узнал об использовании методов расширения C#, чтобы упростить вызов событий, и я использую их все больше и больше. Недавно я столкнулся со странной проблемой, которую я не понимаю, и мне было интересно, может ли кто-нибудь объяснить это.
проблема возникает при попытке установить метод расширения eventhandler в качестве обработчика событий другого события. Вот пример того, что я делаю:
public static class EventHandlerExtensions
{
public static void Raise<TEventArgs>(
this EventHandler<TEventArgs> eventHandler,
object sender, TEventArgs args) where TEventArgs:EventArgs
{
if (eventHandler != null)
{
eventHandler(sender, args);
}
}
}
public class Test
{
private event EventHandler<EventArgs> EventA;
private event EventHandler<EventArgs> EventB;
public Test()
{
Console.WriteLine("::Start");
EventB += EventA.Raise;
EventA += (s, a) => Console.WriteLine("Event A raised");
EventB.Raise(this, EventArgs.Empty);
Console.WriteLine("::End");
}
}
В этом примере EventA должна запускаться в результате Запуск EventB. Однако, когда я запускаю этот код, EventB срабатывает, но метод расширения на A не находит для него прослушивателей.
Если я изменю порядок вокруг, все работает нормально:
Console.WriteLine("::Start");
EventA += (s, a) => Console.WriteLine("Event A raised");
EventB += EventA.Raise;
EventB.Raise(this, EventArgs.Empty);
Console.WriteLine("::End");
кроме того, вызов EventA.Поднять из лямбды отлично работает:
Console.WriteLine("::Start");
EventB += (s, a) => EventA.Raise(s, a);
EventA += (s, a) => Console.WriteLine("Event A raised");
EventB.Raise(this, EventArgs.Empty);
Console.WriteLine("::End");
Это просто простой пример, но я пытаюсь создать класс, который может повторно отправлять события источников событий, добавленных к нему самым чистым способом. Я не хочу создавать им методы только для повторного размещения одних и тех же событий, и я бы предпочел не хранить списки лямбда-функций, которые я могу отцепить от обработчиков событий позже. В основном, мне просто интересно, почему это происходит?
какие идеи?
2 ответов
вы захватываете старое значение EventA в закрытие своей функцией Raise. Поскольку позже вы используете += он изменяет значение EventA, но ваше закрытие все еще имеет старое значение.
код:
EventB += EventA.Raise;
EventA += (s, a) => Console.WriteLine("Event A raised");
может быть расширен в эквивалентный код, который дает понять, почему вы получаете старый делегат:
var oldEventA = EventA;
EventB += oldEventA.Raise; // captures old value here
// now EventA changed to new value
EventA = oldEventA + ((s, a) => Console.WriteLine("Event A raised");)
вы можете добавить следующее до EventB += EventA.Raise
чтобы убедиться, что код действительно вызывает старое событие для:
EventA += (s, a) => Console.WriteLine("Old Event A raised");