WeakEventManager RemoveHandler 在异步调用时并不总是有效

WeakEventManager RemoveHandler does not always work when called asynchronously

我正在使用 Task 中的 WeakEventManager<TEventSource, TEventArgs> class in order to subscribe to events in C#. Event subscription works fine, however calling WeakEventManager<TEventSource, TEventArgs>.RemoveHandler 并不总是删除处理程序 - 大多数(但不是全部)事件触发时处理程序仍在执行。

以下示例对此进行了说明。

public class EventSource
{
    public event EventHandler Fired = delegate { };

    public void FireEvent()
    {
        Fired(this, EventArgs.Empty);
    }
}

class Program
{
    private static bool added, removed, handled;

    static void Main(string[] args)
    {
        for (int i = 1; i <= 100; i++)
        {
            added = removed = handled = false;

            var source = new EventSource();

            AddHandlerAsync(source).Wait();

            RemoveHandlerAsync(source).Wait();

            source.FireEvent();

            if (removed && handled) Console.WriteLine("Event handled after removal!");
            else                    Console.WriteLine("----------------------------");
        }

        Console.ReadKey();
    }

    private async static Task AddHandlerAsync(EventSource source)
    {
        await Task.Run(() =>
        {
            System.Windows.WeakEventManager<EventSource, EventArgs>.AddHandler(source, "Fired", HandleEvent);
            added = true;
        });
    }

    private async static Task RemoveHandlerAsync(EventSource source)
    {
        await Task.Run(() =>
        {
            System.Windows.WeakEventManager<EventSource, EventArgs>.RemoveHandler(source, "Fired", HandleEvent);
            removed = true;
        });
    }

    private static void HandleEvent(object sender, EventArgs e)
    {
        handled = true;
    }
}

处理程序始终被删除,但在大多数情况下,事件仍会得到处理。

我调用这些方法的方式有误吗?这些方法是否支持异步调用?有没有可行的替代方法?

非常感谢您的提前帮助。

这是因为 WeakEventManager 存储在为当前线程 (source) 初始化的当前 WeakEventTable 中:

[ThreadStatic]
private static WeakEventTable   _currentTable;  // one table per thread

并且您使用线程池任务调度程序,它是默认的调度程序。它有时会在同一个线程上调用 AddHandlerRemoveHandler。但有时它会在不同的线程上调用 RemoveHandler 而你有另一个 WeakEventManager 而没有请求的 EventSource.

注意: 如果类型继承自 DispatcherObject,则此类型的实例取决于创建它们的线程。如果 DispatcherObject 是单例,则每个线程创建一个。

因此,如果您看到 DispatcherObject,则仅从创建它的线程调用其方法。否则,你会遇到问题。