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

mic*_*eyt 10 .net c# asynchronous

我正在使用WeakEventManager<TEventSource, TEventArgs>该类来订阅C#中的事件.事件订阅工作正常,但是WeakEventManager<TEventSource, TEventArgs>.RemoveHandler从a 调用Task并不总是删除处理程序 - 当事件触发时处理程序仍然执行的大部分时间(但不是全部).

以下示例说明了这一点.

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

处理程序一直被删除,但在大多数情况下仍然会处理事件.

我是否在调用这些方法时出错?这些方法是否支持异步调用?有没有可行的替代方法?

非常感谢您的帮助.

Yoh*_*all 9

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

[ThreadStatic]
private static WeakEventTable   _currentTable;  // one table per thread
Run Code Online (Sandbox Code Playgroud)

并且您使用线程池任务sheduler,这是默认的sheduler.它呼吁AddHandlerRemoveHandler在同一个线程的时候.但有时它会RemoveHandler在另一个线程上调用,而另一个线程则WeakEventManager没有请求EventSource.

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

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

  • 一个`WeakEventManager`只能在WPF应用程序中正常工作,因为必须存在`Dispatcher`来执行清理操作(`WeakEventManager`使用`Dispatcher.BeginInvoke`).但是如果你想知道如何在控制台应用程序中同步线程,那么请阅读[Await,SynchronizationContext和Console Apps](http://blogs.msdn.com/b/pfxteam/archive/2012/01/20/10259049的.aspx). (3认同)