基本上有两种模式可以避免重复注册事件处理程序: (根据这个讨论:C# pattern to prevent an event handler hooked twice)
使用System.Linq命名空间,并通过调用GetInvocationList().Contains(MyEventHandlerMethod);
在注册之前取消注册,如下所示:
MyEvent -= MyEventHandlerMethod;
MyEvent += MyEventHandlerMethod;
我的问题是,表现方面,哪一个更好,或者他们在表现方面有显着差异?
答案 0 :(得分:5)
我不认为这对假设的绩效增长和实际差异都很重要。
GetInvocationList
和-=
都会遍历内部数组_invocationList
。 (见source)
LINQ扩展方法Contains
将花费更多时间,因为它需要遍历并转换,返回然后由Contains
本身检查整个数组。 Contains
具有以下优势:如果存在,则不需要添加事件处理程序,这将意味着一些性能提升。
答案 1 :(得分: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
的调用列表....