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

标签 c# .net asynchronous

我正在使用 WeakEventManager<TEventSource, TEventArgs> 类以订阅 C# 中的事件。事件订阅工作正常,但是调用 WeakEventManager<TEventSource, TEventArgs>.RemoveHandler 来自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;
    }
}

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

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

非常感谢您的提前帮助。

最佳答案

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

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

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

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

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

关于c# - WeakEventManager RemoveHandler 在异步调用时并不总是有效,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28945510/

相关文章:

c# - 将 Windows 身份验证与声明混合使用

c# - LINQ to Entities - 多个 OrderBy 方法不起作用

c# - 如何将 XML 文档注释添加到 Roslyn 中的 ClassDeclarationSyntax?

c# - 事先检查 `System.Activator.CreateInstance(Of T)` 是否会失败

php - 如何异步运行 PHP 脚本?

java - 异步服务器如何通过释放初始 I/O 线程来增加吞吐量?

c# - 如何从代码隐藏更改 XAML 元素模板?

c# - 如何检测一个对象是一个泛型集合,以及它包含哪些类型?

c# - 获取上下文菜单的控制权

java - 如何指定占位符图像?