2013-04-12 17 views
11

Wenn ich einen Code "fire and forget" machen möchte, aber dennoch sicherstellen möchte, dass mein Speicher bereinigt wird (per Why does asynchronous delegate method require calling EndInvoke?), wird das Folgende das Ziel erreichen?C# Ist action.BeginInvoke (action.EndInvoke, null) eine gute Idee?

Action myAction =() => LongRunTime(); 
myAction.BeginInvoke(myAction.EndInvoke,null); 

Ich habe mich umgesehen, aber habe dieses Muster nirgends gesehen. Stattdessen verwenden Menschen eine Annonomoyus-Methode als Callback (z. B. The proper way to end a BeginInvoke?) oder sie definieren eine tatsächliche Callback-Methode. Da ich niemanden gesehen habe, der das macht, denke ich, dass es entweder nicht funktioniert oder sonst eine schlechte Idee ist.

Danke!

+1

Ich sehe kein Problem mit der Verwendung einer Methodengruppe Konvertierung über einen Lambda-Ausdruck. – Thorarin

+1

Wenn Sie eine Antwort auf die eine oder andere Weise hinzufügen können, wenn diese Technik keinen Speicherverlust verursacht, dann wäre das die Antwort, nach der ich suche. Vielen Dank! –

Antwort

12

Die Verwendung einer Methodengruppenumsetzung anstelle eines Delegaten ist in Ordnung, die EndInvoke wird immer noch auf Ihrem Action aufgerufen werden. Es gibt nichts anderes zu tun, da dies ein Feuer- und Vergessensruf ist.

Leider ist es schwer, direkt zu beweisen, dass EndInvoke aufgerufen wird, da Action ein Delegat ist und wir nicht einfach einen Haltepunkt für eine Klasse in der BCL hinzufügen können.

Dieser Code wird (periodisch) einigen privaten Bereich des IAsyncResult inspiziert, die von BeginInvoke zurückgeführt wird, die Spur davon, ob zu halten scheint oder nicht EndInvoke noch genannt worden ist:

public partial class MainWindow : Window 
{ 
    private Timer _timer = new Timer(TimerCallback, null, 100, 100); 
    private static IAsyncResult _asyncResult; 

    public MainWindow() 
    { 
     InitializeComponent(); 
    } 

    static void LongRunTime() 
    { 
     Thread.Sleep(1000); 
    } 

    void Window_Loaded(object sender, RoutedEventArgs args) 
    { 
     Action myAction =() => LongRunTime(); 
     _asyncResult = myAction.BeginInvoke(myAction.EndInvoke, null); 
    } 

    static void TimerCallback(object obj) 
    { 
     if (_asyncResult != null) 
     { 
      bool called = ((dynamic)_asyncResult).EndInvokeCalled; 
      if (called) 
      { 
       // Will hit this breakpoint after LongRuntime has completed 
       Debugger.Break(); 
       _asyncResult = null; 
      } 
     } 
    } 
} 

ich doppelt habe geprüft unter Verwendung SOS, dass es keine verwalteten Speicherlecks gibt. Ich habe auch einige andere Beweise versucht, aber sie waren umständlicher als diese, denke ich.

Einige interessante ich während meiner Untersuchung entdeckt: die myAction.BeginInvoke Aufruf wird auf Profiler mit Instrumentierung angezeigt, aber myAction.EndInvoke nicht.

+0

Es gibt keinen Grund, dass ich sehen kann. Rufen Sie LongRunTime() direkt in der Aufgabe auf. –

+3

Die Aufgabe war neben dem Punkt, aber hier ist ein Beispiel ohne eine Aufgabe, wenn Sie bevorzugen. – Thorarin

+0

+1 Danke Thorarin! Große Details und Forschung! –

Verwandte Themen