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