我在 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
最佳答案
我认为这两个代码片段是相同的,我们在这里没有任何关于强引用/弱引用的问题。
背景
首先,如果我们的 Interop.ComObjectWrapper
提供 CLR 事件(即在委托(delegate)中存储事件处理程序的事件),我们肯定会从 ComObjectWrapper
获得一个强引用到我们的目标。
任何委托(delegate)都包含两部分:类型为object
的Target
和指向特定方法的方法指针。如果 Target
为 null
,则回调指向静态方法。
Target
类型为 WeakReference 的委托(delegate)是不可能的.有所谓的Weak Event Pattern但它在 EventManager 之上实现而不是普通代表。
在字段中存储事件处理程序无济于事。第 1 部分
内部事件实现是指订阅事件后:
comObject.SomeEvent += EventCallback;
comObject
对象隐含地持有对 SomeClass
对象的强引用。 无论您使用何种订阅技术,无论 ComObject 是否为 COM 对象包装器,都是如此。
订阅事件会在生命周期方面增加两个对象之间的隐式依赖性。这就是为什么 .NET 世界中最常见的内存泄漏是由订阅长生命周期对象的事件引起的。 在应用程序中访问事件持有者之前,事件订阅者不会死亡。
在字段中存储事件处理程序无济于事。第二部分
但是如果我的假设不成立并且 ComObjectWrapper
提供了一些弱事件模式的概念,那么在现场保存事件处理程序将无济于事。
让我们回顾一下事件关键字的含义:
private event ComEventHandler comEventHandler;
...
comEventHandler = new ComEventHandler(EventCallback);
在当前字段中保存回调(基本上我们可以将私有(private)事件视为一个简单的委托(delegate)字段)不会改变现有行为。
我们已经知道委托(delegate)是一个简单的对象,它存储对 Target 对象(即 SomeClass
对象)的引用和一个方法(即 public void EventCallBack()
)。这意味着在字段中存储额外的委托(delegate)会从 SomeClass
本身添加对 SomeClass
的额外引用。
基本上,在字段中存储事件处理程序在语义上等同于在 SomeClass 中存储附加引用:
私有(private)的一些类一些类;
公共(public) SomeClaas() { //这与存储委托(delegate)基本相同 //在 comEventHandler 字段中 一些类=这个;
在 SomeClass
中存储强引用不会延长当前对象的生命周期。 这意味着如果 ComObjectWrapper
不会持有强引用引用 comEventHandler
中存储事件处理程序的 SomeClass
对象不会延长 SomeClass 的生命周期,也不会阻止 SomeClass
进行垃圾回收。
结论
将事件处理程序存储在私有(private)字段中不会延长对象的生命周期,也不会阻止它进行垃圾回收。
这就是为什么以下代码片段在对象生命周期方面没有区别的原因:
// GOOD!
comObject.SomeEvent += new ComEventHandler(EventCallback);
// EVEN BETTER!
comObject.SomeEvent += EventCallback;
// NOT GOOD, BECAUSE WAN'T HELP!
comEventHandler = new ComEventHandler(EventCallback);
comObject.SomeEvent += comEventHandler
关于c# - 将事件分配给事件处理程序的两种不同类型的区别,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13567692/