将事件分配给事件处理程序的两种不同类型之间的差异



我在SO中看到了这个示例代码,它说一种做法不好,另一种做法好。但我不明白为什么?事实上,我收到了著名的RCW COM对象错误,那篇帖子说这可能是一个原因。

public class SomeClass
{
private Interop.ComObjectWrapper comObject;
private event ComEventHandler comEventHandler;
public SomeClass()
{
comObject = new Interop.ComObjectWrapper();
// NO - BAD!
comObject.SomeEvent += new ComEventHandler(EventCallback);
// YES - GOOD!
comEventHandler = new ComEventHandler(EventCallback);
comObject.SomeEvent += comEventHandler
}
public void EventCallback()
{
// DO WORK
}

}

编辑:这是指向源的链接:COM对象已与其底层RCW分离,不能使用

我认为这两个代码片段是相同的,我们在这里没有任何强/弱引用的问题。

背景

首先,如果我们的Interop.ComObjectWrapper提供CLR事件(即在委托中存储事件处理程序的事件),我们肯定会从ComObjectWrapper获得对对象的强引用。

任何委托都包含两部分:类型为objectTarget和指向特定方法的方法指针。如果Targetnull,则回调指向静态方法。

不可能有一个具有类型为WeakReference的Target的委托。有所谓的弱事件模式,但它是在EventManager之上实现的,而不是普通的委托。

在字段中存储事件处理程序没有帮助。第1部分

内部事件实现意味着订阅事件后:

comObject.SomeEvent += EventCallback;

comObject对象隐含地持有对SomeClass对象的强引用无论您使用哪种订阅技术,无论ComObject是否是COM对象包装器,这都是正确的

订阅事件会增加两个对象之间在生存期方面的隐式依赖关系。这就是最常见的内存泄漏的原因。NET世界由订阅长寿命对象的事件引起在应用程序中可访问事件持有者之前,事件订阅者不会死亡

在字段中存储事件处理程序没有帮助。第2部分

但是,如果我的假设不成立,并且ComObjectWrapper提供了弱事件模式的一些概念,那么在字段中保存事件处理程序将毫无帮助。

让我们回顾一下事件关键字的含义:

private event ComEventHandler comEventHandler;
... 
comEventHandler = new ComEventHandler(EventCallback);

将回调保存在当前字段中(基本上我们可以将私有事件视为简单的委托字段)不会改变现有行为。

我们已经知道delegate是一个简单的对象,它存储对Target对象(即SomeClass对象)和方法(即public void EventCallBack())的引用。这意味着在字段中存储额外的委托会从SomeClass本身添加对SomeClass的额外引用。

基本上,在字段中存储事件处理程序在语义上等同于在SomeClass:中存储附加引用

私人SomeClass SomeClass;

公共SomeClaas(){//这与存储委托基本相同//在comEventHandler字段中someClass=this;}

SomeClass中存储强引用不会延长当前对象的寿命这意味着,如果ComObjectWrapper不会在comEventHandler中保存对存储事件处理程序的SomeClass对象的强引用,则不会延长SomeClass的生存期,也不会阻止SomeClass进行垃圾收集。

结论

将事件处理程序存储在私有字段中不会延长对象的生存期,也不会阻止它进行垃圾收集。

这就是为什么以下代码片段在对象生存期方面没有区别:

// GOOD!
comObject.SomeEvent += new ComEventHandler(EventCallback);
// EVEN BETTER!
comObject.SomeEvent += EventCallback;
// NOT GOOD, BECAUSE WAN'T HELP!
comEventHandler = new ComEventHandler(EventCallback);
comObject.SomeEvent += comEventHandler

最新更新