Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can you use equals assignment when removing delegate members in a disposing method?

I have the following code in my class

public class Receiver : IReceiver
{

    public event EventHandler Received;

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(bool disposing)
    {
        if (disposing)
        {
            if (Received != null)
            {
                foreach (EventHandler delegateMember in Received.GetInvocationList())
                {
                    Received -= delegateMember;
                }
            }
        }
    }
}

This code works in that when I dispose my class any events that are hooked up to the Received event, will be removed individually.

I've been wondering if rather than being so verbose about it, if the following terse version will have the same effect

    protected virtual void Dispose(bool disposing)
    {
        if (disposing)
        {
            Received = null;
        }
    }

Basically this comes down to how the operator overloads have been created by Microsoft when implementing the delegate overloads. I know that all the documentation says to use the += to subscribe and -= to unsubscribe from an event. I've also seen the document say that the event will be assigned to null when the last subscriber is removed. What the documentation does not say is whether assigning the event to null, will have the effect of unsubscribing all the events?

I'd love to know if this is possible, and if there is any documentation that says that the possible terse code is correct behaviour.

Update:

I've been doing some more digging with the c# compiler and have found that the assignment to null only works within the class where the event is defined. The += and -= is always available from both inside and outside the class. This leads me to be thinking that using the = null version is acceptable. However, this is speculation, I still have not seen any documentation that states explicitly states this is supported functionality.

like image 942
Colin Dawson Avatar asked May 27 '15 15:05

Colin Dawson


1 Answers

There's no reason not to just assign null to the delegate here.

You wouldn't be able to just assign null if you were outside of the class that defined the event. To anyone using the class they should only be concerned with their own handlers, that they can add or remove. They aren't able to access the handlers of others.

You need to remember that delegates are immutable. Using += on an event doesn't mutate the delegate to add a new method to that delegate, it creates a new delegate that, when invoked, calls both of the delegates that were added together. Using -= creates a delegate that invokes all of the invocations of the first operand except for the second operand. So calling -= over and over is continually creating more and more delegates that each invoke less and less stuff, until eventually you get to the point that the delegate isn't invoking anything anymore. Just assigning null is equivalent to just creating a delegate that does nothing, and assigning that directly.

So when you call -= over and over the original delegate that was assigned to the event before you started still exists, as well as N intermediate delegates. That said, none of the delegates are likely to be referenced by any rooted element, so they'll all be eligible for collection. If you just assign null you still have the same orphaned delegate that was originally there, you just don't have any of those intermediate delegates anymore.

like image 51
Servy Avatar answered Oct 03 '22 00:10

Servy