Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Do custom events need to be set to null when disposing an object?

Tags:

c#

events

dispose

Lets says we have 2 objects, Broadcaster and Listener. Broadcaster has an event called Broadcast to which Listener is subscribed. If Listener is disposed without unsubscribing from the Broadcast event it will be retained in memory because of the event delegate referencing it that Broadcaster contains.

What I'm curious about is if Broadcaster is disposed without Listener unsubscribing or Broadcaster setting Broadcast = null will Broadcaster be retained in memory?

I have not been able to locate anything with a hard answer to this question except one blogger who believes that not setting the event to null will keep the source in memory (found here).

I'd like to hear an explanation of why or why not.

Thanks.

UPDATE: Forum Thread where one developer indicates events should be set to null, but Jon Skeet indicates it's not necessary, but doesn't elaborate.

like image 693
Dan Rigby Avatar asked Jan 05 '10 22:01

Dan Rigby


People also ask

Does Dispose set object to NULL?

When an object implements IDisposable you should call Dispose (or Close , in some cases, that will call Dispose for you). You normally do not have to set objects to null , because the GC will know that an object will not be used anymore.

How do you Dispose a variable in C#?

Answers. We don't dispose the variables. In case if there are any unmanaged resources (or the ones which are inherited from IDisposable) can have Dispose() calls. In your case, you may have simple string or other primitive datatypes - these are not the ones which implement IDisposable interface.

How use Dispose method in C#?

The Dispose() methodThe Dispose method performs all object cleanup, so the garbage collector no longer needs to call the objects' Object. Finalize override. Therefore, the call to the SuppressFinalize method prevents the garbage collector from running the finalizer. If the type has no finalizer, the call to GC.

How check object is disposed or not in C#?

The object must not throw an exception if its Dispose method is called multiple times. Instance methods other than Dispose can throw an ObjectDisposedException when resources are already disposed." msdn.microsoft.com/en-us/library/… @HansPassant: If an object implements IDisposable , one can call (IDisposable.


2 Answers

Note that delegates don't keep the publisher alive (they only keep the target=subscriber alive), so no number of subscriptions will (by themselves) keep the broadcaster alive. As such, from this perspective it doesn't matter whether it is disposed or not. When there are no items referencing the broadcaster (and the event-subscriptions don't matter for this), it will be eligible for collection.

Essentially, a delegate is a (list of) pair(s) of MethodInfo and object references; the method to call, and the object to invoke as "arg0" (aka this). It simply doesn't have a reference to the object raising the event.

Here's evidence that a listener does not keep the source alive; you should see that "Source 1" gets collected, even though we still have the matching listener that is subscribed. As expected, "Listener 2" does not get collected, since we still have the matching broadcaster:

class DataSource
{
    public DataSource(string name) { this.name = name; }
    private readonly string name;
    ~DataSource() { Console.WriteLine("Collected: " + name); }

    public event EventHandler SomeEvent;
}
class DataListener
{
    public DataListener(string name) { this.name = name; }
    private readonly string name;
    ~DataListener() { Console.WriteLine("Collected: " + name); }
    public void Subscribe(DataSource source)
    {
        source.SomeEvent += SomeMethodOnThisObject;
    }
    private void SomeMethodOnThisObject(object sender, EventArgs args) { }
}

static class Program
{
    static void Main()
    {
        DataSource source1 = new DataSource("Source 1"),
                source2 = new DataSource("Source 2");
        DataListener listener1 = new DataListener("Listener 1"),
                listener2 = new DataListener("Listener 2");
        listener1.Subscribe(source1);
        listener2.Subscribe(source2);
        // now we'll release one source and one listener, and force a collect
        source1 = null;
        listener2 = null;
        GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
        GC.WaitForPendingFinalizers(); // source 1 gets collected, ONLY

        Console.WriteLine("Done");
        Console.ReadLine();
        GC.KeepAlive(source2); // prevents collection due to optimisation
        GC.KeepAlive(listener1); // prevents collection due to optimisation
    }
}
like image 116
Marc Gravell Avatar answered Oct 20 '22 08:10

Marc Gravell


No. The delegate target in the Broadcast event references the Listener object. That will keep the Listener object alive. The Listener object doesn't have any reference back to the Broadcast object.

Watch out for terminology. Disposing the Broadcast object does nothing. It has to be garbage collected which can only happen when there's no references left to the object. When that happens, the delegate object will automatically be collected as well since the only reference to it is the internal list of delegate targets maintained by private event delegate object. That also removes the reference the delegate has to the listener. If there are no other references to the listener, it will be collected as well. If it still is, it will just no longer get event notifications. Long story short: you don't have to explicitly set the event to null in the Broadcast class.

Not quite the same in the listener, it is referenced by the event it subscribed to. If it is declared unfit for business (disposed) but the broadcaster is still live then it should remove its event subscription explicitly. The SystemEvents class is an extreme version of that, its events are static. Firing events on a delegate that references a disposed listener is something you tend to notice.

Most practical object models try to ensure listener objects disappear when the parent goes. Windows Forms would be a good example. No need to explicitly unsubscribe events then.

like image 43
Hans Passant Avatar answered Oct 20 '22 10:10

Hans Passant