2010-07-15 3 views
8

Können Sie Nachteile dieses One-Liner andere als die Tatsache sehen, dass mehrere Verwendungen davon das Prinzip DRY verletzen würde? Es scheint einfach, aber die Tatsache, dass ich nicht gesehen habe, dass andere es vorschlagen, lässt mich fragen, ob es einen Nachteil gibt.Ein Liner: WeakReference-to-a-Lambda Event-Handler

Dieses Codebeispiel erstellt eine WeakReference für eine Methode und registriert dann einen Ereignishandler, der das Ziel der Referenz aufruft.

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

Danke,
Ben

+0

Haben Sie meine Frage/Antwort [hier] (http://stackoverflow.com/questions/1747235/weak-event-handler-model-for-use-with-lambdas) gesehen? Es ist kein One-Liner, aber ich denke * es funktioniert ... – Benjol

Antwort

11

Ich glaube nicht, dass dieses Muster das tut, was Sie erwarten. Möchten Sie verhindern, dass das Ereignis einen Verweis auf das aktuelle Objekt enthält, um Speicherlecks zu vermeiden? Der Lambda-Ausdruck erfasst den Wert this, um ProcessEvent auszuwerten (vorausgesetzt, ProcessEvent ist eine Instanzmethode), so dass Sie immer noch das Leck haben. Dieser Code ist der gleiche wie SomeEvent += (sender, e) => ProcessEvent();.

Möglicherweise versuchen Sie, etwas mehr wie dies zu tun (was auch nicht das, was Sie wollen):

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

die WeakReference Jetzt fängt der Lambda-Ausdruck, so dass Sie nicht eine starke Referenz haben zu this. Leider verweist nichts anderes auf den Delegat, der von ProcessEvent erstellt wurde, daher wird er auch beim nächsten GC entfernt, auch wenn this noch aktiv ist. (Dies überprüft auch nicht, ob das Ziel null ist).

Man könnte so etwas wie dies versucht:

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; 
} 

und es dann wie folgt verwenden:

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

, dass ein schwachen Bezug auf den Empfänger von Process halten wird, und wird das Ereignis automatisch entfernen Handler des Ereignisses, nachdem es gesammelt wurde, was Speicherlecks verhindern sollte, solange das Ereignis regelmäßig ausgelöst wird.

+0

Dies funktioniert nicht für jedes Ereignis. Sie müssen es für das * exact * -Ereignis spezialisieren, das Sie benötigen, beispielsweise EventArgs durch PropertyChangedEventArgs und EventHandler durch PropertyChangedEventHandler zu ersetzen. Ich habe versucht, eine generische Version zu erstellen, wo Sie die Typen übergeben konnten, aber das schien nicht zu funktionieren. –

0

Es ist nicht sehr gut lesbar. Und wenn Sie es debuggen müssen, indem Sie durchgehen, könnte eine dieser Aktionen fehlschlagen, aber diese einzelne Zeile würde fehlschlagen. Außerdem erhalten Sie nur diese einzelne Zeile, auf die in einer Stack-Trace verwiesen wird.

Sie möchten in der Regel vermeiden, zu viele Dinge in einer einzigen Zeile für die Wartbarkeit zu tun.