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