何时何地在VB.NET中调用RemoveHandler?

时间:2010-04-27 12:45:54

标签: .net vb.net event-handling dispose

我正在使用.NET 1.1中的VB.NET windows forms projet。我有这种类型的架构,非常简化。

Public MustInherit Class BaseTestLogic

  Private _TimerPoll As Timer

  Public Sub New(ByVal sym As SymbolFileMng, ByVal cfg As LampTestConfig, ByVal daas As DaasManager, ByVal mcf As Elux.Wg.Lpd.MCFs.VMCF)

    AddHandler _TimerPoll.Tick, AddressOf TimerPoll_Tick

  End Sub

End Class

Public Class SpecificTestLogic
  Inherits BaseTestLogic      

End Class

根据我正在进行的测试类型,我创建了一个源自 BaseTestLogic 的特定测试的实例。但我发现在经过数百次对象创建后,我可以拥有 StackOverflow 异常。

我检查了我的代码,发现我忘了删除处理程序到Timer Tick。问题是,删除hadler的地点和时间是否正确?

我是否需要在基类中实现 IDisposable 接口,在 Dispose 中实现RemoveHandler?

6 个答案:

答案 0 :(得分:0)

如果你在构造函数中添加它们,那么在Dispose中删除它们是正确的,但它当然取决于你的设计。

这是一个问题,提供有关何时需要担心删除它们的信息 AddHandler/RemoveHandler Not Disposing Correctly

答案 1 :(得分:0)

您可以在调用Dispose时同时删除处理程序,但是纯粹主义者会说“除了处理非托管资源之外,您不应该滥用IDisposable”。

另一种选择是在 Finalize 方法中删除处理程序。

如果在您的设计中有任何意义,您也可以放心在几个不同的地方删除处理程序。删除已删除的处理程序不会导致任何问题 - 除非事件是自定义事件且其AddHandler / RemoveHandler实现与非自定义事件的行为不匹配(这只是使用[Delegate] .CombineDelegate / [Delegate]) 。去掉)。只是不要告诉你的纯粹朋友;他们不会遵守。

答案 2 :(得分:0)

这是一个老问题,但我是通过网络搜索来实现的,所以它仍然是一个关于计时器的有用问题。对您的问题没有给出适当的答案。答案提供给您的问题,但问题是错误的。您的问题应该是:如何禁用计时器,以便不再触发事件?

Dim WithEvents timer1作为新的Timer()

(然后将timer1_Elapsed添加到您的代码中)

这解决了担心IDisposable或Finalize的问题,因为为您管理了Timer事件处理程序。当您不再需要计时器时,请设置Enabled = False或调用Stop()方法以防止它滴答作响。

答案 3 :(得分:0)

Timer 类设计器实现 IDisposable 的决定必须被视为一种声明,即实现处理对非 .NET 的某种形式的引用API / raw 操作系统资源分配(抱歉非规范面额)。

正如@supercat 所提到的,只要事件发布者存在,事件订阅者就会一直保持活动状态,这会导致引用更大生命周期对象的问题,如 In vb.net, if I use AddHandler, Do I have to use RemoveHandler? 中所述,并且 不是,因为事件处理程序是非托管资源

事件处理程序不是在 .NET 术语中使用的意义上的“非托管资源”,而不是“托管”:不需要通过显式分配管理FinalizeDispose() 用于资源释放和清理。

来自 Troelsen 2010 Pro C#:

<块引用>

终结器可以用来释放 垃圾收集器启动时的非托管资源。 然而, 鉴于许多非托管对象是“宝贵的项目”(例如原始 数据库或文件句柄),尽快释放它们可能很有价值 尽可能而不是依赖垃圾收集来发生。作为 替代覆盖 Finalize(),您的类可以实现 IDisposable 接口,它定义了一个名为 Dispose()

勘误表:见Is unwired event a memory leak? 因此,回到问题,如果 TimerPoll_Tick 事件处理程序属于更大的生命周期对象,则永远不会释放 BaseTestLogic 实例。我不确定,但即使 TimerPoll_TickBaseTestLogic 静态方法,也可能会发生这种情况。

回到问题,stackoverflow 异常似乎很奇怪,可能与 TimerPoll_Tick 事件处理中的某种形式的设计失败有关,而不是与 @GideonEngelberth 建议的对象生命周期问题有关。

答案 4 :(得分:-1)

我的第一个想法是,您的实际问题与添加和删除事件处理程序几乎没有关系。 StackOverflowException意味着您有一系列函数正在创建无限循环的递归调用。您发布的代码并未显示可能发生的任何地方,但异常的堆栈跟踪应指向违规代码。

根据您关于创建派生类型测试的评论,我想知道您是否可以从基类中的构造函数发布更多代码。

答案 5 :(得分:-1)