vb.net - example - Maneja vs. AddHandler
garbage collector c# example (7)
Acoplo manualmente controladores cuando creo controles manualmente (por ejemplo, crear dinámicamente un cuadro de texto para cada registro de base de datos). Desconecto manualmente a los controladores cuando están manejando cosas que aún no estoy lista para manejar (¿posiblemente porque estoy usando los eventos incorrectos? :))
¿Existe una ventaja para los controladores de eventos de conexión / separación dinámica?
¿Los controladores de separación manual ayudarían a garantizar que no haya una referencia restante para un objeto eliminado?
Declarar un campo como WithEvents
hará que el compilador genere automáticamente una propiedad con ese nombre. El getter devuelve el valor de un campo de respaldo. El colocador es un poco más complicado. Primero verifica si el campo de respaldo ya tiene el valor correcto. Si es así, sale. De lo contrario, si el campo de respaldo no es nulo, emite solicitudes "RemoveHandler" para todos sus eventos al objeto identificado por el campo de respaldo. A continuación, independientemente de si el campo de respaldo no fue nulo, lo establece igual al valor solicitado. Finalmente, si el nuevo valor no es nulo, ya sea el anterior o no, la propiedad emite solicitudes de "AddHandler" para todos sus eventos al objeto identificado por el nuevo valor.
Siempre que uno configure todos los miembros WithEvents de un objeto en Nothing
antes de abandonarlo, y evite manipular los miembros WithEvents en varios hilos, el código de evento generado automáticamente no se fugará.
Desconectar manualmente un evento puede ser importante para evitar fugas de memoria: el objeto que se conecta a un evento disparado por otro objeto, no será recolectado como basura hasta que el objeto que dispara el evento sea basura recolectada. En otras palabras, un "evento-raiser" tiene una fuerte referencia a todos los "oyentes del evento" conectados a él.
Encuentro que los controladores de eventos de vinculación / separación dinámicamente solo se usan cuando se tiene un objeto de larga duración que expone eventos que son consumidos por muchos objetos efímeros. Para la mayoría de los otros casos, los dos objetos se eliminan en el mismo momento y el CLR hace un trabajo suficiente de limpieza por sí mismo.
La mayoría de las veces el marco se ocupa de eso por usted.
No se trata de usar AddHandler versus Handles.
Si le preocupa la referencia a su controlador de eventos que interfiere con la recolección de basura, debe usar RemoveHandler, independientemente de cómo se adjuntó el controlador. En el método Dispose del formulario o control, elimine cualquier controlador.
He tenido situaciones en las aplicaciones de Windows Forms (.NET 1.1 días) donde se llamaría a un controlador de eventos en los controles que no tenían otras referencias a ellos (y que para todos los efectos estaban muertos y yo habría pensado que se habían sometido a GC) - extremadamente difícil de depurar.
Usaría RemoveHandler para deshacerme de los controladores en controles que no vas a volver a utilizar.
Estoy bastante seguro de que la cláusula Handles
es simplemente azúcar sintáctica e inserta una declaración AddHandler
en tu constructor. Probé usando este código y deshabilité el marco de la aplicación para que el constructor no tuviera elementos adicionales:
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
El IL terminó así:
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
Observe dos bloques idénticos de código alrededor de IL_000b e IL_0051. Creo que es solo azúcar sintáctico.