我有一个类来处理来自WinForms控件的事件.根据用户正在做的事情,我正在引用该类的一个实例并创建一个新实例来处理同一事件.我需要先从事件中取消订阅旧实例 - 这很容易.如果可能的话,我想以非专有方式这样做,看起来这是IDisposable的工作.但是,大多数文档仅在使用非托管资源时才建议使用IDisposable,这在此处不适用.
如果我实现IDisposable并取消订阅Dispose()中的事件,我是否会歪曲它的意图?我应该提供一个Unsubscribe()函数并调用它吗?
编辑:这是一些虚拟代码,它显示了我正在做的事情(使用IDisposable).我的实际实现与一些专有数据绑定(长篇故事)有关.
class EventListener : IDisposable { private TextBox m_textBox; public EventListener(TextBox textBox) { m_textBox = textBox; textBox.TextChanged += new EventHandler(textBox_TextChanged); } void textBox_TextChanged(object sender, EventArgs e) { // do something } public void Dispose() { m_textBox.TextChanged -= new EventHandler(textBox_TextChanged); } } class MyClass { EventListener m_eventListener = null; TextBox m_textBox = new TextBox(); void SetEventListener() { if (m_eventListener != null) m_eventListener.Dispose(); m_eventListener = new EventListener(m_textBox); } }
在实际代码中,"EventListener"类涉及更多,每个实例都具有独特的重要性.我在集合中使用它们,并在用户点击时创建/销毁它们.
结论
我接受gbjbaanb的回答,至少目前如此.我觉得使用熟悉的界面的好处超过了在没有涉及非托管代码的情况下使用它的任何可能的缺点(这个对象的用户怎么会知道?).
如果有人不同意 - 请发帖/评论/编辑.如果可以对IDisposable做出更好的论证,那么我将改变接受的答案.
是的,去吧.虽然有些人认为IDisposable仅针对非托管资源实现,但事实并非如此 - 非托管资源恰好是最大的胜利,也是实现它的最明显的理由.我认为它获得了这个想法,因为人们无法想到使用它的任何其他原因.它不像一个性能问题的终结器,并且GC不易处理.
在您的dispose方法中添加任何整理代码.它会更清晰,更清晰,更有可能防止内存泄漏,并且比试图记住取消引用更容易正确使用.
IDisposable的目的是让您的代码更好地工作,而无需您进行大量的手动工作.使用它的力量对你有利,并克服一些人为的"设计意图"废话.
我记得当.NET首次出现时,很难说服微软确定最终确定的有用性 - 我们赢得了战斗并说服他们添加它(即使它当时只是一种设计模式),使用它!
我的个人投票是使用Unsubscribe方法从事件中删除类.IDisposable是一种用于确定性释放非托管资源的模式.在这种情况下,您不管理任何非托管资源,因此不应实现IDisposable.
IDisposable可用于管理事件订阅,但可能不应该.举个例子,我指向WPF.这是一个充满活动和事件处理程序的图书馆.然而,WPF中几乎没有类实现IDisposable.我认为这表明应该以另一种方式管理事件.
使用IDisposable
模式取消订阅事件困扰我的一件事是Finalization问题.
Dispose()
函数in IDisposable
应该由开发人员调用,但是如果它没有被开发人员调用,那么可以理解GC将调用这个函数(IDisposable
至少通过标准模式).但是,在你的情况下,如果你不打电话,Dispose
其他人就不会 - 事件仍然存在且强引用使GC无法调用终结器.
在Dispose
我看来,()不会自动调用()的事实似乎足以在这种情况下不使用IDisposable.也许它需要一个新的特定于应用程序的接口,该接口说这种类型的对象必须具有一个由GC处理的清理函数.