2010-07-15 9 views
8

¿Puedes ver las desventajas de este one-liner que no sea el hecho de que los usos múltiples de él violarían el principio DRY? Parece sencillo, pero el hecho de que no haya visto a otros proponerlo me hace preguntarme si hay un inconveniente.One Liner: WeakReference-a-un controlador de eventos de Lambda

Este fragmento de código crea un WeakReference a un método y luego registra un controlador de eventos que invoca el objetivo de la referencia.

SomeEvent += (sender, e) => ((Action)(new WeakReference((Action)ProcessEvent)).Target)(); 

Gracias,
Ben

+0

¿Has visto mi pregunta/respuesta [aquí] (http://stackoverflow.com/questions/1747235/weak-event-handler-model-for-use-with-lambdas)? No es de una sola línea, pero creo * que funciona ... – Benjol

Respuesta

11

No creo que ese patrón haga lo que esperas. ¿Está tratando de evitar que el evento contenga una referencia al objeto actual para evitar fugas de memoria? La expresión lambda capturará el valor de this para evaluar ProcessEvent (suponiendo que ProcessEvent es un método de instancia), por lo que aún tendrá la fuga. Este código es el mismo que en SomeEvent += (sender, e) => ProcessEvent();.

Puede estar intentando hacer algo de la misma familia (que tampoco es lo que desea):

var reference = new WeakReference((Action)ProcessEvent); 
SomeEvent += (sender, e) => ((Action)reference.Target)(); 

Ahora la expresión lambda capturará la WeakReference, por lo que no tendrá una fuerte referencia a this. Desafortunadamente, nada más está haciendo referencia al delegado creado desde ProcessEvent, por lo que se eliminará en el siguiente GC incluso si this aún está activo. (Esto tampoco verifica que Target sea nulo).

Usted podría intentar algo como esto:

public EventHandler MakeWeakHandler(Action action, Action<EventHandler> remove) 
{ 
    var reference = new WeakReference(action.Target); 
    var method = action.Method; 
    EventHandler handler = null; 
    handler = delegate(object sender, EventArgs e) 
    { 
     var target = reference.Target; 
     if (target != null) 
     { 
      method.Invoke(target, null); 
     } 
     else 
     { 
      remove(handler); 
     } 
    }; 
    return handler; 
} 

y luego usarlo como esto:

SomeEvent += MakeWeakHandler(ProcessEvent, h => SomeEvent -= h); 

que mantendrá una referencia débil al receptor de ProcessEvent, y eliminará automáticamente el evento manejador del evento después de que se haya recopilado, lo que debería evitar pérdidas de memoria siempre y cuando el evento se eleve regularmente.

+0

Esto no funciona para ningún evento. Debe especializarlo para el evento * exact * que necesite, por ejemplo, reemplazar EventArgs con PropertyChangedEventArgs y EventHandler con PropertyChangedEventHandler. Intenté crear una versión genérica en la que pudiera pasar los tipos pero eso no parecía funcionar. –

0

No es muy fácil de leer. Y si tiene que depurarlo al pasar, cualquiera de esas acciones podría fallar, pero esa única línea fallaría. Además, solo obtendrá esa única línea a la que se hace referencia en un seguimiento de pila.

Por lo general, desea evitar hacer demasiadas cosas en una sola línea para el mantenimiento.

Cuestiones relacionadas