我在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 object that has been separated from its underlying RCW cannot be used
答案 0 :(得分:4)
我认为这两个代码段是相同的,我们在这里没有强/弱引用的任何问题。
首先,如果我们的Interop.ComObjectWrapper
提供CLR事件(即在代理中存储事件处理程序的事件),我们肯定会从ComObjectWrapper
获得对我们对象的强引用。
任何委托包含两部分:类型Target
的{{1}}和特定方法的方法指针。如果object
为Target
,则回调指向静态方法。
无法拥有null
类WeakReference的代理人。有一个所谓的Weak Event Pattern,但它实现在EventManager之上而不是普通代表。
内部事件实现意味着在订阅事件后:
Target
comObject.SomeEvent += EventCallback;
对象隐含地强烈引用comObject
对象。 无论您正在使用何种订阅技术以及ComObject是否是COM对象包装器,都是如此。
订阅事件会在生命周期中添加两个对象之间的隐式依赖关系。这就是为什么.NET世界中最常见的内存泄漏是由订阅长期存在的对象的事件引起的。 活动订阅者不会在应用程序中可访问事件持有者之前死亡。
但是如果我的假设不正确并且SomeClass
提供了弱事件模式的概念,那么事件在场中保存事件处理程序将无济于事。
让我们回顾一下事件关键字的含义:
ComObjectWrapper
在当前字段中保存回调(基本上我们可以将私有事件视为简单的委托字段)不会更改现有行为。
我们已经知道委托是一个简单的对象,它存储对Target对象(即private event ComEventHandler comEventHandler;
...
comEventHandler = new ComEventHandler(EventCallback);
对象)和方法(即SomeClass
)的引用。这意味着在字段中存储其他委托会为public void EventCallBack()
本身的SomeClass
添加额外的引用。
基本上,在字段中存储事件处理程序在语义上等同于在SomeClass中存储附加引用:
private SomeClass someClass;
public SomeClaas() { //这与存储委托基本相同 //在comEventHandler字段中 someClass = this; }
在SomeClass
中存储强引用不会延长当前对象的生命周期。这意味着如果SomeClass
不能保留对{{1}的强引用在ComObjectWrapper
中存储事件处理程序的对象不会延长SomeClass的生命周期,也不会阻止SomeClass
进行垃圾回收。
在私有字段中存储事件处理程序不会延长对象的生命周期,也不会阻止它进行垃圾回收。
这就是为什么以下代码片段在对象生存期方面没有区别:
comEventHandler