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

本文关键字:可以避免 事件处理 程序 性能 模式 更好 哪种 | 更新日期: 2023-09-27 18:35:48

基本上

有两种模式可以避免重复注册事件处理程序:(根据此讨论:防止事件处理程序挂钩两次的 C# 模式)

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

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

    MyEvent -= MyEventHandlerMethod;
    MyEvent += MyEventHandlerMethod;
    
我的问题是,在性能

方面,哪一个更好,或者它们在性能上存在显着差异?

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

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

GetInvocationList-=_invocationList内部阵列。(见来源)

LINQ 扩展方法Contains将花费更多时间,因为它需要遍历和转换、返回整个数组,然后由Contains本身进行检查。Contains的优点是,如果存在,则不需要添加事件处理程序,这意味着性能会有所提高。

  1. 不适用于外部呼叫者,并且无论如何效率都不是很高
  2. 应该没问题(请注意,它每次都会创建 2 个委托实例),但也要考虑
  3. 在大多数情况下,应该很容易知道你是否已经订阅;如果你不知道,那么这表明存在架构问题。
典型的用法是"订阅

{某些用法}[取消订阅]",其中取消订阅可能不是必需的,具体取决于事件发布者和订阅者的相对生存期;如果您实际上有一个重入方案,那么"如果尚未订阅,则订阅"本身就是有问题的,因为稍后取消订阅时,您不知道是否阻止了外部迭代接收事件。

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

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

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

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

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

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

相关文章: