将事件分配给事件处理程序的两种不同类型之间的区别 [英] Difference between two different types of assigning events to event handlers

查看:156
本文介绍了将事件分配给事件处理程序的两种不同类型之间的区别的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在SO中看到这个示例代码是说一个实践是坏的,另一个是好的。但我不明白为什么?
事实上,我得到了这个着名的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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆