哪种C#模式具有更好的性能以避免重复的事件处理程序?

时间:2014-12-30 10:39:16

标签: c# eventhandler

基本上有两种模式可以避免重复注册事件处理程序: (根据这个讨论:C# pattern to prevent an event handler hooked twice

  1. 使用System.Linq命名空间,并通过调用GetInvocationList().Contains(MyEventHandlerMethod);

  2. 检查事件处理程序是否已注册
  3. 在注册之前取消注册,如下所示:

    MyEvent -= MyEventHandlerMethod;
    MyEvent += MyEventHandlerMethod;
    
  4. 我的问题是,表现方面,哪一个更好,或者他们在表现方面有显着差异?

4 个答案:

答案 0 :(得分:5)

我不认为这对假设的绩效增长和实际差异都很重要。

GetInvocationList-=都会遍历内部数组_invocationList。 (见source

LINQ扩展方法Contains将花费更多时间,因为它需要遍历并转换,返回然后由Contains本身检查整个数组。 Contains具有以下优势:如果存在,则不需要添加事件处理程序,这将意味着一些性能提升。

答案 1 :(得分:4)

  1. 不适用于外部呼叫者,并且效率不高无论如何
  2. 应该没问题(请注意,每次创建2个委托实例),但也要考虑
  3. 在大多数情况下,应该很容易知道您是否已经订阅;如果你不知道,则表明存在架构问题
  4. 典型用法是“订阅{某些用法} [取消订阅]”,根据活动发布者和订阅者的相对生命周期,可能不需要取消订阅;如果你真的有一个可重入的场景,那么“订阅,如果尚未订阅”本身就有问题,因为当以后取消订阅时,你不知道你是否阻止了外部迭代接收事件

答案 2 :(得分:2)

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

因此,在最坏的情况下,GetInvocationList().Contains(MyEventHandlerMethod);的操作是O(1)(因为我们只是获得了数组的引用)+ O(n)用于搜索方法,即使没有优化也是如此为了它。我非常怀疑这是真的,我认为有一些优化代码,它是O(log_n)

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

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

答案 3 :(得分:2)

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

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