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