Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Difference between two dispose implementations?

Is there a difference between these two implementations?

1 :

public class SMSManager : ManagerBase
{
    private EventHandler<SheetButtonClickEventArgs> _buttonClickevent; 

    public SMSManager(DataBlock smsDataBlock, DataBlock telephonesDataBlock) :
        base(smsDataBlock)
    {
        _buttonClickevent = new EventHandler<SheetButtonClickEventArgs>(OnButtonClick);
        SheetEvents.ButtonClick += _buttonClickevent;

    }

    public override void Dispose()
    {
        base.Dispose();
        if (_buttonClickevent != null)
        SheetEvents.ButtonClick -= _buttonClickevent;
    }
}

2 :

public class SMSManager : ManagerBase
{
    public SMSManager(DataBlock smsDataBlock, DataBlock telephonesDataBlock) :
        base(smsDataBlock)
    {
        SheetEvents.ButtonClick += new EventHandler<SheetButtonClickEventArgs>(OnButtonClick);   
    }

    public override void Dispose()
    {
        base.Dispose();
        SheetEvents.ButtonClick -= new EventHandler<SheetButtonClickEventArgs>(OnButtonClick);
    }
}

The first one seems to be more correct than the second in regards to memory leaks. But is it really correct?

like image 458
julien29 Avatar asked May 22 '12 15:05

julien29


1 Answers

The long and short of it is the second piece of code is correct and safe (even if there are no handlers registered).

Consider this sample app:

namespace ConsoleApplication61
{
    class Program
    {
        static void Main(string[] args)
        {
            var f = new Foo();
            f.MyEvent += new EventHandler(Handler);
            f.Trigger();
            f.MyEvent -= new EventHandler(Handler);
            f.Trigger();
            Console.Read();
        }

        static void Handler(object sender, EventArgs e)
        {
            Console.WriteLine("handled");
        }
    }

    class Foo
    {
        public event EventHandler MyEvent;
        public void Trigger()
        {
            if (MyEvent != null)
                MyEvent(null, null);
        }
    }
}

This sample prints "handled" once.

So in your example, they are functionally the same and both will work as needed. Removing a handler that hasn't been added is also a safe action, it simply finds nothing to remove and does nothing.

As provided in the comments, Marc's answer goes into more detail:

Unregister events with new instance of the delegate


Event Handlers with Anonymous Methods

It is worth noting that event handlers in the form of lambda expressions are not guaranteed to enforce uniqueness based on instance and method signature. If you need to unsubscribe an anonymous method, you either need to promote it to a method or keep a reference to the anonymous method for later use:

Func<object, EventArgs> meth = (s, e) => DoSomething();

myEvent += meth;
myEvent -= meth;

Jon Skeet goes into detail answering this and likely does a better job of it than me :-)

How to remove a lambda event handler


A Slight Refactoring

I would refactor to the following:

public class SMSManager : ManagerBase
{
    public SMSManager(DataBlock smsDataBlock, DataBlock telephonesDataBlock) 
        : base(smsDataBlock)
    {
        SheetEvents.ButtonClick += OnButtonClick;   
    }

    public override void Dispose()
    {
        SheetEvents.ButtonClick -= OnButtonClick;
        base.Dispose();
    }
}
like image 113
Adam Houldsworth Avatar answered Oct 19 '22 02:10

Adam Houldsworth