12

避免重复注册事件处理程序基本上有两种模式:(根据这个讨论:C#模式防止事件处理程序被钩住两次

  1. 使用 System.Linq 命名空间,并通过调用检查事件处理程序是否已注册GetInvocationList().Contains(MyEventHandlerMethod);

  2. 在注册之前进行注销,如下所示:

    MyEvent -= MyEventHandlerMethod;
    MyEvent += MyEventHandlerMethod;
    

我的问题是,在性能方面,哪个更好,或者它们之间的性能有显着差异?

4

4 回答 4

5

我认为这并不重要,无论是假设的性能增益还是实际的差异。

两者都GetInvocationList-=内部数组_invocationList。(见来源

LINQ 扩展方法Contains将花费更多时间,因为它需要遍历和转换整个数组,返回然后Contains自行检查。它Contains的优点是不需要添加事件处理程序(如果存在),这将意味着一些性能提升。

于 2014-12-30T10:49:49.837 回答
4
  1. 对外部调用者不起作用,而且效率也不
  2. 应该没问题(请注意,它每次都会创建 2 个委托实例),但也要考虑
  3. 在大多数情况下,应该很容易知道您是否已经订阅;如果你不知道,那么这表明存在架构问题

典型的用法是“subscribe {some usage} [unsubscribe]”,其中可能不需要取消订阅,具体取决于事件发布者和订阅者的相对生命周期;如果您实际上有一个可重入场景,那么“如果尚未订阅则订阅”本身就是有问题的,因为稍后取消订阅时,您不知道您是否正在阻止外部迭代接收事件。

于 2014-12-30T10:55:35.687 回答
2

MyEvent -= MyEventHandlerMethod首先需要在调用列表中找到注册的事件处理程序才能将其删除。所以GetInvocationList().Contains更好,但它确实微不足道。

但是,请注意您无法访问event EventHandler foo的调用列表....

于 2014-12-30T10:51:31.827 回答
2

根据文档,调用列表被存储为数组或类似的东西,并且事件处理程序的顺序也被存储。可能存在内部结构来保持快速搜索的特定方法。

因此,在最坏的情况下,GetInvocationList().Contains(MyEventHandlerMethod);is O(1)(因为我们只是得到了数组的引用)+O(n)用于搜索方法,即使没有对其进行优化。我严重怀疑这是真的,我认为有一些优化代码,它是O(log_n).

第二种方法有额外的添加操作,我认为,O(1)当我们将事件处理程序添加到末尾时。

因此,要查看这些操作之间的区别,您需要大量的事件处理程序。
但是!如果您使用第二种方法,正如我所说,您会将事件处理程序添加到 queue 的末尾,这在某些情况下可能是错误的。所以使用第一个,毫无疑问。

于 2014-12-30T10:50:26.987 回答