简体   繁体   English

具有LINQ和委托约束的WeakEventHandler

[英]WeakEventHandler with LINQ and delegate constraint

How can a C# generic weak event handler be made for predefined system events using LINQ? 如何使用LINQ为预定义的系统事件创建C#通用弱事件处理程序? Solution 4 of Daniel Grunwald's article on Weak Events in C# shows a reusable wrapper, ie Daniel Grunwald关于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
);

However, an attempt to apply this to a generic event such as the UnhandledExceptionHandler results in a compile error: Cannot implicitly convert type 'System.EventHandler' to 'System.UnhandledExceptionEventHandler' . 但是,尝试将此方法应用于诸如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));

ConvertTo in Jacob Carpenter's article on Delegate Conversion may provide a clue, but I currently do not see how to use that with Daniel Grunwald's code. 雅各布·卡彭特(Jacob Carpenter)关于委托转换的文章中的ConvertTo可能提供了一个线索,但是我目前尚不知道如何将其与Daniel Grunwald的代码一起使用。

I am not familiar with what you are trying to do here but I did experiment some to get this to compile. 我对您要在此处执行的操作并不熟悉,但是我做了一些实验以使其编译。

WeakEventHandler can work with either EventHandler or EventHandler<TEventArgs> . WeakEventHandler可以与EventHandlerEventHandler<TEventArgs> The signature for an event handler of EventHandler<UnhandledExceptionEventArgs> matches the signature for UnhandledExceptionEventHandler . EventHandler<UnhandledExceptionEventArgs>的事件处理程序的签名与UnhandledExceptionEventHandler的签名匹配。

Because the 2 signatures are identical, we can convert one to the other using the TransformHandler function below. 因为这两个签名是相同的,所以我们可以使用下面的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)
);

You will have to try this out and see if it actually works for what you need. 您将不得不尝试一下,看看它是否真正适合您的需求。

Combining CastDelegate as ConvertDelegate into WeakEventHandler did the trick. 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;
    }
}

Example usage witih PropertyChangedEventHandler would be as follows: PropertyChangedEventHandler的示例用法如下:

WeakEventHandler<PropertyChangedEventHandler, PropertyChangedEventArgs>.Register(
    textDocument,
    (d, eh) => d.PropertyChanged += eh,
    (d, eh) => d.PropertyChanged -= eh,
    this,
    (me, sender, args) => me.OnPropertyChanged(sender, args)
    );

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM