将事件分配给事件处理程序的两种不同类型之间的区别 [英] Difference between two different types of assigning events to event handlers
问题描述
事实上,我得到了这个着名的RCW COM对象错误,该帖子说这可能是一个原因。
public class SomeClass
{
private Interop.ComObjectWrapper comObject;
私人事件ComEventHandler comEventHandler;
public SomeClass()
{
comObject = new Interop.ComObjectWrapper();
//不 - 坏!
comObject.SomeEvent + = new ComEventHandler(EventCallback);
//是 - 好!
comEventHandler = new ComEventHandler(EventCallback);
comObject.SomeEvent + = comEventHandler
}
public void EventCallback()
{
// DO WORK
}
}
编辑:这里是源的链接:一直以来的COM对象与其底层RCW分开不能使用
我认为这两个代码片段是一样的,
背景
首先,如果我们的 Interop.ComObjectWrapper
提供CLR事件(即在代理中存储事件处理程序的事件),我们一定会从 ComObjectWrapper
任何委托包含两个部分:目标
类型为对象
和方法Pointe r到具体方法。如果
Target
是 null
比回调指向静态方法。
不可能有一个代表 Target
的类型为 WeakReference 。有所谓的弱活动模式,但它实现在 EventManager ,而不是普通的代理。
在该字段中存储事件处理程序将无济于事。第1部分
内部事件实施意味着在订阅事件后:
comObject.SomeEvent + = EventCallback;
comObject
对象隐含着强烈的引用 SomeClass
对象。 这是真的,无论您使用什么样的订阅技术,以及ComObject是否是COM对象包装器。
订阅事件在生命周期中增加两个对象之间的隐式依赖关系。这就是为什么.NET世界中最常见的内存泄漏是由订阅长命期的对象的事件引起的。 事件订阅者不会在应用程序中访问事件持有者之前死亡。
在该字段中存储事件处理程序将无济于事。第2部分
但事件如果我的假设不是真的,而 ComObjectWrapper
提供了一些弱事件模式的概念,保存事件这个字段中的处理程序不会有任何帮助。
让我们总结一下事件关键字的意思:
私人活动ComEventHandler comEventHandler;
...
comEventHandler = new ComEventHandler(EventCallback);
在当前字段中保存回调(基本上我们可以将私人事件视为一个简单的委托字段)不会改变现有行为。
我们已经知道委托是一个简单的对象,它存储对Target对象的引用(即 SomeClass
object)和一个方法(即 public void EventCallBack()
)。这意味着在字段中存储额外的委托将增加对 SomeClass
本身的 SomeClass
的引用。
基本上,在字段中存储事件处理程序语义相当于在SomeClass中存储额外的引用:
private SomeClass someClass;
public SomeClaas()
{
//这与在comEventHandler字段中存储委托
//基本相同
someClass =这个;
}
在 SomeClass
中存储强引用不会延长当前对象的生命周期。这意味着如果 ComObjectWrapper
不会强制引用 SomeClass
对象存储事件处理程序在 comEventHandler
不会延长SomeClass的生命周期,并且不会阻止垃圾回收中的 SomeClass
。
结论
在私有域中存储事件处理程序不会延长对象的生命周期,也不会阻止垃圾回收。
这就是为什么以下代码片段在对象生命期方面没有区别:
// GOOD!
comObject.SomeEvent + = new ComEventHandler(EventCallback);
//甚至更好!
comObject.SomeEvent + = EventCallback;
//不好,请谅解!
comEventHandler = new ComEventHandler(EventCallback);
comObject.SomeEvent + = comEventHandler
I saw this sample code in SO that was saying one practice is bad and the other one is good. But I don't understand why? As a matter of fact I am getting that famous RCW COM object error and that post was saying this could be a reason.
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
}
}
Edit: here is the link to the source: COM object that has been separated from its underlying RCW cannot be used
I think those two code snippets are the same and we don't have any issues with strong/weak references here.
Background
First of all, if our Interop.ComObjectWrapper
provides CLR event (i.e. event that stores event handlers in delegates) we'll definitely got a strong reference from ComObjectWrapper
to our object.
Any delegate contains two parts: Target
of type object
and Method Pointer to the particular method. If Target
is null
than callback points to the static method.
Its impossible to have a delegate with Target
of type WeakReference. There is so called Weak Event Pattern but it implements on top of EventManager instead of plain delegates.
Storing event handler in the field will not help. Part 1
Internal event implementation means that after subscribing to the event:
comObject.SomeEvent += EventCallback;
comObject
object implicitely holds an strong reference to the SomeClass
object. And this true regardless of what kind of subscribing technique your are using and whether ComObject is a COM object wrapper or not.
Subscribing to the event adds implicit dependency between two objects in terms of lifetime. That's why the most common memory leak in .NET world caused by subscribing to events of the long-lived objects. Event subscriber will not die till event holder accessible in the application.
Storing event handler in the field will not help. Part 2
But event if my assumption is not true and ComObjectWrapper
provides some notion of Weak Event Pattern, saving event handler in the field will not help any way.
Lets recap what event keyword mean:
private event ComEventHandler comEventHandler;
...
comEventHandler = new ComEventHandler(EventCallback);
Saving callback in current field (and basically we can treat private events as a simple delegate fields) will not change existing behavior.
We already know that delegate is a simple object that stores reference to the Target object (i.e. SomeClass
object) and a method (i.e. public void EventCallBack()
). This means that storing additional delegate in field adds additional reference to the SomeClass
from the SomeClass
itself.
Basically, storing event handler in the field semantically equivalent to storing additional reference in SomeClass:
private SomeClass someClass;
public SomeClaas() { // This is basically the same as storing delegate // in the comEventHandler field someClass = this; }
Storing strong reference in the SomeClass
will not prolong lifetime of the current object. And this means that if ComObjectWrapper
will not hold a strong reference to the SomeClass
object storing event handler in the comEventHandler
will not prolong SomeClass's lifetime and will not prevent SomeClass
from garbage collection.
Conclusion
Storing event handler in the private field will not prolong object's lifetime and will not prevent it from garbage collection anyway.
That's why there is no difference between following code snippets in terms of object lifetime:
// GOOD!
comObject.SomeEvent += new ComEventHandler(EventCallback);
// EVEN BETTER!
comObject.SomeEvent += EventCallback;
// NOT GOOD, BECAUSE WAN'T HELP!
comEventHandler = new ComEventHandler(EventCallback);
comObject.SomeEvent += comEventHandler
这篇关于将事件分配给事件处理程序的两种不同类型之间的区别的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!