如何使用LINQ为预定义的系统事件创建C#泛型弱事件处理程序? Daniel Grunwald关于Weak Events in C#的文章的解决方案4显示了一个可重复使用的包装器,即
eventWrapper = WeakEventHandler.Register(
eventSource,
(s, eh) => s.Event += eh, // registering code
(s, eh) => s.Event -= eh, // deregistering code
this, // event listener
(me, sender, args) => me.OnEvent(sender, args) // forwarding code
);
但是,尝试将此应用于通用事件(例如UnhandledExceptionHandler)会导致编译错误:无法将类型'System.EventHandler'隐式转换为'System.UnhandledExceptionEventHandler'。
WeakEventHandler.Register(AppDomain.CurrentDomain,
(s, eh) => s.UnhandledException += eh,
(s, eh) => s.UnhandledException -= eh,
this,
(me, sender, ea) => me.UnhandledExceptionHandler(sender, ea));
Jacob Carpenter关于Delegate Conversion的文章中的ConvertTo可能提供了线索,但我目前还没有看到如何在Daniel Grunwald的代码中使用它。
答案 0 :(得分:1)
我不熟悉你在这里尝试做什么,但我做了一些实验,以便编译。
WeakEventHandler可以使用EventHandler
或EventHandler<TEventArgs>
。 EventHandler<UnhandledExceptionEventArgs>
的事件处理程序的签名与UnhandledExceptionEventHandler
的签名匹配。
由于2个签名相同,我们可以使用下面的TransformHandler
函数将其中一个转换为另一个。
public static UnhandledExceptionEventHandler TransformHandler(EventHandler<UnhandledExceptionEventArgs> handler)
{
return new UnhandledExceptionEventHandler(handler);
}
WeakEventHandler<UnhandledExceptionEventArgs>.Register(
AppDomain.CurrentDomain,
(s, eh) => s.UnhandledException += TransformHandler(eh),
(s, eh) => s.UnhandledException -= TransformHandler(eh),
this,
(me, sender, ea) => me.UnhandledExceptionHandler(sender, ea)
);
你必须尝试这一点,看看它是否真的能满足你的需要。
答案 1 :(得分:0)
将CastDelegate与ConvertDelegate合并为WeakEventHandler就可以了。
/// <summary>
/// Helper class to add weak handlers to events of predefined event handler, i.e. PropertyChagnedEventHandler
/// </summary>
public static class WeakEventHandler<TEventHandler, TEventArgs>
where TEventHandler : class // delegate
// where TEventArgs : EventArgs // work with structs not derived from EventArgs, i.e. DependencyPropertyChangedEventArgs
{
/// <summary>
/// Registers an predefined event handler that works with a weak reference to the target object.
/// Access to the event and to the real event handler is done through lambda expressions.
/// The code holds strong references to these expressions, so they must not capture any
/// variables!
/// </summary>
/// </example>
public static WeakEventHandler Register<TEventSource, TEventListener>(
TEventSource senderObject,
Action<TEventSource, TEventHandler> registerEvent,
Action<TEventSource, TEventHandler> deregisterEvent,
TEventListener listeningObject,
Action<TEventListener, object, TEventArgs> forwarderAction
)
where TEventSource : class
where TEventListener : class
{
if (senderObject == null) throw new ArgumentNullException("senderObject");
if (listeningObject == null) throw new ArgumentNullException("listeningObject");
WeakEventHandler.VerifyDelegate(registerEvent, "registerEvent");
WeakEventHandler.VerifyDelegate(deregisterEvent, "deregisterEvent");
WeakEventHandler.VerifyDelegate(forwarderAction, "forwarderAction");
WeakEventHandler weh = new WeakEventHandler(listeningObject);
TEventHandler eh = MakeDeregisterCodeAndWeakEventHandler(weh, senderObject, deregisterEvent, forwarderAction);
registerEvent(senderObject, eh);
return weh;
}
static TEventHandler MakeDeregisterCodeAndWeakEventHandler
<TEventSource, TEventListener>
(
WeakEventHandler weh,
TEventSource senderObject,
Action<TEventSource, TEventHandler> deregisterEvent,
Action<TEventListener, object, TEventArgs> forwarderAction
)
where TEventSource : class
where TEventListener : class
{
Action<object, TEventArgs> eventHandler = (sender, args) =>
{
TEventListener listeningObject = (TEventListener)weh.listeningReference.Target;
if (listeningObject != null) forwarderAction(listeningObject, sender, args);
else weh.Deregister();
};
weh.deregisterCode = delegate
{
deregisterEvent(senderObject, ConvertDelegate(eventHandler));
};
return ConvertDelegate(eventHandler);
}
static TEventHandler ConvertDelegate(Delegate source)
{
if (source == null) return null;
Delegate[] delegates = source.GetInvocationList();
if (delegates.Length == 1) return Delegate.CreateDelegate(typeof(TEventHandler), delegates[0].Target, delegates[0].Method) as TEventHandler;
for (int i = 0; i < delegates.Length; i++) delegates[i] = Delegate.CreateDelegate(typeof(TEventHandler), delegates[i].Target, delegates[i].Method);
return Delegate.Combine(delegates) as TEventHandler;
}
}
示例用法witih PropertyChangedEventHandler如下:
WeakEventHandler<PropertyChangedEventHandler, PropertyChangedEventArgs>.Register(
textDocument,
(d, eh) => d.PropertyChanged += eh,
(d, eh) => d.PropertyChanged -= eh,
this,
(me, sender, args) => me.OnPropertyChanged(sender, args)
);