【问题标题】:Difference between two dispose implementations?两个 dispose 实现之间的区别?
【发布时间】:2012-05-22 15:03:19
【问题描述】:

这两种实现有区别吗?

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

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

【问题讨论】:

  • 不要忘记将答案标记为答案,它有助于丰富本站的内容。

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


【解决方案1】:

总而言之,第二段代码是正确且安全的(即使没有注册处理程序)。

考虑这个示例应用:

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

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

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

正如 cmets 中所提供的,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();
    }
}

【讨论】:

  • @SwDevMan81 宾果游戏!我一直在寻找那个信息,ta。
  • 这就是为什么我们都在这里闲逛 :) 总是在学习新事物
  • @All 有趣的是带有匿名方法的事件处理程序(新时尚),它们玩得不太好。我是前几天才知道的。
  • @SwDevMan81 在这个网站上学习新事物的一个(也是唯一一个)问题是检查旧代码(或昨天编写的代码)以查看你是否犯了你没有犯的错误。当时不知道哈哈!这种情况发生的次数...
  • @Adam - 哈哈是真的。我有 666 个答案,所以我让邪恶的旧代码继续存在:P
猜你喜欢
  • 2017-07-01
  • 1970-01-01
  • 1970-01-01
  • 2010-12-27
  • 2014-08-01
  • 1970-01-01
  • 2013-11-22
  • 1970-01-01
  • 2011-11-01
相关资源
最近更新 更多