将两种不同类型的事件分配给事件处理程序的区别
我在SO中看到了这个示例代码,它说一个练习很糟糕而另一个很好。 但我不明白为什么? 事实上,我得到了那个着名的RCW COM对象错误,该post说这可能是一个原因。
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 }
}
编辑:这是源的链接: 不能使用已与其基础RCW分离的COM对象
我认为这两个代码片段是相同的,我们在这里没有强/弱引用的任何问题。
背景
首先,如果我们的Interop.ComObjectWrapper
提供了CLR事件(即在委托中存储事件处理程序的事件),我们肯定会从ComObjectWrapper
到我们的对象获得强引用。
任何委托包含两部分:类型object
和特定方法的方法指针。 如果Target
为null
,则回调指向静态方法。
不可能有一个类型为WeakReference的 Target
的委托。 有一种所谓的弱事件模式,但它实现在EventManager之上,而不是普通的委托。
在字段中存储事件处理程序将无济于事。 第1部分
内部事件实现意味着在订阅事件之后:
comObject.SomeEvent += EventCallback;
comObject
对象隐含地拥有对SomeClass
对象的强引用。 无论您使用何种订阅技术以及ComObject是否是COM对象包装器,这都是正确的。
订阅事件会在生命周期中添加两个对象之间的隐式依赖关系。 这就是为什么.NET世界中最常见的内存泄漏是由订阅长期对象的事件引起的。 在应用程序中可访问事件持有者之前,事件订阅者不会死
在字段中存储事件处理程序将无济于事。 第2部分
但事件如果我的假设不正确并且ComObjectWrapper
提供了一些弱事件模式的概念,那么在字段中保存事件处理程序将无济于事。
让我们回顾一下event关键字的含义:
private event ComEventHandler comEventHandler; ... comEventHandler = new ComEventHandler(EventCallback);
在当前字段中保存回调(基本上我们可以将私有事件视为简单的委托字段)不会更改现有行为。
我们已经知道委托是一个简单的对象,它存储对Target对象(即SomeClass
对象)和方法(即public void EventCallBack()
)的public void EventCallBack()
。 这意味着在字段中存储附加委托会从SomeClass
本身添加对SomeClass
附加引用。
基本上,在字段中存储事件处理程序在语义上等同于在SomeClass中存储其他引用:
private SomeClass someClass;
public SomeClaas(){//这与在comEventHandler字段中存储委托//基本相同someClass = this; }
在SomeClass
存储强引用不会延长当前对象的生命周期。 这意味着如果ComObjectWrapper
不能保存对SomeClass
对象的强引用,那么在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