2012-03-02 18 views
5

Tengo una bastante corto pregunta sobre controladores de eventos anónimos:controladores de eventos anónimo y desechar

Este es el código que tengo:

public void AddTestControl(Control ctrl) 
{ 
    ctrl.Disposed += (o, e) => { RemoveTestControl(ctrl); }; 
    ctrl.SomeEvent += _Control_SomeEvent; 
} 

public void RemoveTestControl(Control ctrl) 
{ 
    ctrl.SomeEvent -= _Control_SomeEvent; 
} 

Es éste el código de multa, o Si el Código ser reescrito para eliminar el controlador de eventos Disposed? Algo como esto:

public void AddTestControl(Control ctrl) 
{ 
    ctrl.Disposed += _Control_Disposed; 
    ctrl.SomeEvent += _Control_SomeEvent; 
} 

public void RemoveTestControl(Control ctrl) 
{ 
    ctrl.Disposed -= _Control_Disposed; 
    ctrl.SomeEvent -= _Control_SomeEvent; 
} 

Respuesta

8

En general, la única situación en la que es necesario eliminar los controladores de eventos de un objeto con el fin de que sea elegible para la recolección de basura es cuando el editor objeto (la definición de la evento) vive más tiempo que el objeto del suscriptor (el que contiene los controladores de eventos). En tal situación, el GC no podrá liberar al suscriptor cuando salga del alcance, ya que el editor aún hace referencia a él.

En este caso, suponiendo que esto es WebForms o WinForms, el editor (que es el objeto Control), es más probable que un objeto niño del abonado (probablemente un Page o una Form), que será la primera salir del alcance llevándose todos sus objetos asociados. Por lo tanto, hay sin necesidad de eliminar los controladores de eventos.

+0

afaik nadie promete el orden de ejecución de los controladores de eventos. – b0rg

+0

Pero mi pregunta es más sobre el evento Disposed. ¿Debo separarlo o la primera muestra de código está bien? – juFo

+1

@juFo Suponiendo que la razón por la que pregunta es porque le preocupan las pérdidas de memoria, entonces ** no, no necesita separar los manejadores de eventos usted mismo **. Como el objeto 'Control' tiene el mismo tiempo de vida que el' Page' o 'Form' que contiene los manejadores de eventos, saldrán del alcance juntos. –

2

Siempre siente más limpio para mí darse de baja de los acontecimientos, incluso en situaciones en las que sé que los abonados siempre sobreviven a la editor (el objeto provocar el evento): el evento no será levantado de nuevo, el editor ya no es alcanzable y se puede recopilar.

Por otra parte,, ¿cuántas personas se toman la molestia de cancelar la suscripción de cada controlador de eventos en, por ejemplo, una aplicación WinForms? Las referencias de objeto apuntan desde el editor a los suscriptores, y no al revés, por lo que el editor se puede recopilar mientras los suscriptores viven. No presenta el mismo peligro que el opuesto a situación, donde un editor de larga duración (por ejemplo, un evento estático) puede malgastar la vida de suscriptores potencialmente grandes mucho tiempo después de que puedan haberse recopilado.

Si desea/necesita darse de baja, el requisito de darse de baja del mismo delegado hace que los controladores de eventos anónimos se sientan un poco molestos. El Reactive Extensions resuelve este problema de una manera ordenada: en lugar de tener que recordar al delegado al que se suscribió, la suscripción devuelve un IDisposable que anula la suscripción cuando se desecha. Al tirar todas sus suscripciones a un CompositeDisposable, puede cancelar la suscripción de todo con solo una llamada Dispose.

1

Ambos codez están bien, pero me gusta en segundo lugar como una cuestión de preferencia personal. Se lee más claro que el primero.

En la parte superior con el primer código, hay un delegado lambda anónimo y obtiene una referencia actual de ctrl. Ese código puede comportarse de forma inesperada dependiendo de la situación y de la configuración de optimización de compilación: tanto si la llamada está en línea como si no.

Sin mencionar que hay un problema arquitectónico con el código: usted tiene ControlOwner y un montón de Child Controls.Supongo que está agregando controles secundarios a ControlOwner en tiempo de ejecución, y luego tratando de reaccionar ante su comportamiento suscribiendo ControlOwner a los eventos de childControl. Esto está bien para eventos como _ButtonClicked, etc., pero no es bueno para Dispose. Deje que el niño controle el manejo que está desechando sobre sí mismo, OwnerControl no necesita saberlo. Sin mencionar que puede no existir a la vez que se llama ChildControl [n] .Dispose.

En resumen: * que es mejor dejar disponer de sucesos en ChildControl solo y hacer todo lo hacen limpieza en ChildControl.Dispose * no es necesario darse de baja de eventos. El despachador del evento verificará si el suscriptor está vivo.

Cuestiones relacionadas