Difference between two different types of assignin

2019-07-04 11:47发布

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

标签: c# events com
1条回答
家丑人穷心不美
2楼-- · 2019-07-04 12:28

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
查看更多
登录 后发表回答