句柄与AddHandler
时间:2020-03-05 18:51:48 来源:igfitidea点击:
动态添加/分离事件处理程序是否有优势?
手动分离处理程序是否有助于确保没有剩余的对已处置对象的引用?
解决方案
回答
在大多数情况下,框架都会为我们解决这个问题。
回答
手动分离事件对于防止内存泄漏很重要:连接到另一个对象触发的事件的对象将不会被垃圾回收,除非触发该事件的对象被垃圾回收。换句话说,"事件引发器"对与其连接的所有"事件监听器"都有很强的参考意义。
回答
我发现动态添加/分离事件处理程序仅在我们有一个长期对象公开许多短寿命对象消耗的事件的情况下才有用。在大多数其他情况下,这两个对象放置在同一时间,CLR会自行完成清理工作
回答
我很确定Handles
子句只是语法糖,并将AddHandler
语句插入到构造函数中。我使用此代码进行了测试,并禁用了应用程序框架,因此构造函数将没有多余的东西:
Public Class Form1 Public Sub New() ' This call is required by the Windows Form Designer. ' InitializeComponent() ' Add any initialization after the InitializeComponent() call. ' AddHandler Me.Load, AddressOf Form1_Load End Sub Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load Dim breakpoint As Integer = 4 End Sub End Class
IL最终如下所示:
IL_0000: nop IL_0001: ldarg.0 IL_0002: call instance void [System.Windows.Forms]System.Windows.Forms.Form::.ctor() IL_0007: nop IL_0008: ldarg.0 IL_0009: ldarg.0 IL_000a: dup IL_000b: ldvirtftn instance void WindowsApplication1.Form1::Form1_Load(object, class [mscorlib]System.EventArgs) IL_0011: newobj instance void [mscorlib]System.EventHandler::.ctor(object, native int) IL_0016: call instance void [System.Windows.Forms]System.Windows.Forms.Form::add_Load(class [mscorlib]System.EventHandler) '... lots of lines here ' IL_0047: ldarg.0 IL_0048: callvirt instance void WindowsApplication1.Form1::InitializeComponent() IL_004d: nop IL_004e: ldarg.0 IL_004f: ldarg.0 IL_0050: dup IL_0051: ldvirtftn instance void WindowsApplication1.Form1::Form1_Load(object, class [mscorlib]System.EventArgs) IL_0057: newobj instance void [mscorlib]System.EventHandler::.ctor(object, native int) IL_005c: callvirt instance void [System.Windows.Forms]System.Windows.Forms.Form::add_Load(class [mscorlib]System.EventHandler) IL_0061: nop IL_0062: nop IL_0063: ret } // end of method Form1::.ctor
注意IL_000b和IL_0051周围的两个相同的代码块。我认为这只是语法糖。
回答
这不是使用AddHandler与Handles的问题。
如果我们担心干扰垃圾回收的事件处理程序的引用,则无论使用何种处理程序,都应使用RemoveHandler。在窗体或者控件的Dispose方法中,删除所有处理程序。
我在Windows Forms应用程序中遇到过这样的情况(.NET 1.1天),在没有其他引用的控件上将调用事件处理程序(并且出于所有意图和目的,这些控件已经死了,我以为是GC'ed -极难调试。
我将使用RemoveHandler摆脱不打算重用的控件上的处理程序。
回答
手动创建控件时(例如,为每个数据库记录动态创建一个TextBox)时,我会手动添加处理程序。当处理程序处理我还没有准备好处理的事情时,我会手动分离它们(可能是因为我使用了错误的事件?:))