两个部署实现之间的区别?

时间:2012-05-22 15:03:19

标签: c# memory-leaks delegates event-handling dispose

这两种实现有区别吗?

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);
    }
}

在内存泄漏方面,第一个似乎比第二个更正确。但它真的是对的吗?

1 个答案:

答案 0 :(得分:5)

它的长短是第二段代码是正确和安全的(即使没有注册处理程序)。

考虑这个示例应用程序:

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);
        }
    }
}

此示例打印“处理”一次。

因此,在您的示例中,它们在功能上是相同的,并且两者都将根据需要工作。删除尚未添加的处理程序也是一个安全的操作,它只是找不到任何要删除的内容并且什么都不做。

正如评论中所提到的,Marc的回答更详细:

Unregister events with new instance of the delegate


使用匿名方法的事件处理程序

值得注意的是,lambda表达式形式的事件处理程序无法保证基于实例和方法签名强制实现唯一性。如果您需要取消订阅匿名方法,则需要将其提升为方法或保留对匿名方法的引用以供以后使用:

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

myEvent += meth;
myEvent -= meth;

Jon Skeet详细回答这个问题并且可能比我做得更好: - )

How to remove a lambda event handler


轻微重构

我会重构以下内容:

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

    public override void Dispose()
    {
        SheetEvents.ButtonClick -= OnButtonClick;
        base.Dispose();
    }
}