2017-03-29 3 views
0

Wenn ich diesen Code alles laufen funktioniert:Async Await Equivalent

public async void InvokePlugin(MyObject xTask) 
{ 
    try 
    { 
     var hndlr = new TimeoutHandler(RunTask); 
     var asyncResult = hndlr.BeginInvoke(xTask, null, new object()); 
     if (!asyncResult.AsyncWaitHandle.WaitOne(xTask.Timeout, false)) 
     { 
      throw new TimeoutException("Plugin didn't complete processing in a timely manner."); 
     } 
     hndlr.EndInvoke(asyncResult); 
    } 
    catch (Exception ex) 
    { 
     //Handle Exceptions 
    } 
} 

private delegate void TimeoutHandler(MyObject xTask); 

ich diesen Code aktualisieren möchten Async/Await zu verwenden. Ich versuchte es so:

public async void InvokePlugin(MyObject xTask) 
{ 
    try 
    { 
     var runTask = Task.Run(() => { RunTask(xTask); }); 
     if (await Task.WhenAny(runTask, Task.Delay(xTask.Timeout)) == runTask) 
     { 
      // Task completed within timeout. 
      // Consider that the task may have faulted or been canceled. 
      // We re-await the task so that any exceptions/cancellation is rethrown. 
      await runTask; 
     } 
     else 
     { 
      throw new TimeoutException("Plugin didn't complete processing in a timely manner."); 
     } 
    } 
    catch (Exception ex) 
    { 
     //Handle Exceptions 
    } 
} 

... aber es funktioniert nicht. Klar mache ich etwas wring. Es ruft die RunTask-Methode auf und führt die ersten zwei Zeilen aus, aber dann endet es einfach und ich kann die Ausnahme weder in der TaskRun-Methode noch im obigen Code abfangen. Alles, was ich in den Ausgabefenstern sehe, ist "Programm wurde mit Code 0 (0x0) beendet."

Wenn die Experten da draußen entweder auf das hinweisen, was ich falsch mache, oder mir Vorschläge machen, wie ich die Ausnahme fangen und behandeln kann, wäre ich sehr dankbar.

Auch wenn Sie das Gefühl haben, dass ich irgendwelche wichtigen Details verpasst habe, fragen Sie bitte und ich werde meine Frage aktualisieren.

Normalerweise würde ich sagen, wenn es funktioniert, repariere es nicht, aber in diesem Fall versuche ich ein wenig zu rearchitect, um einige Verbesserungen zu erlauben, also bin ich hier.

+3

Das erste, was mir aufgefallen ist, vermeide Signaturen mit 'async void'. Verwenden Sie stattdessen 'async Task', damit der Anrufer etwas erwarten kann. Die einzige Ausnahme sind Ereignishandler in WPF- und WinForms-Apps. – Igor

+6

'erwarten' ist nicht dasselbe wie' Warten'. Ihr ursprünglicher Code ist synchron ('WaitOne'), daher kann er nicht in' async/await' umgewandelt werden. –

+3

1) Ändern Sie "async void" in "async Task". 2) "erwarten" die Aufgabe, so dass Async wachsen kann. 3) Rufen Sie in Ihrer 'Main' Methode 'GetAwaiter(). GetResult()' auf der "Top" Task auf. –

Antwort

3
  1. Änderung async void zu async Task. Siehe meinen Artikel auf async best practices für weitere Informationen.

Nachdem Sie dies tun, verbrauchen sie asynchron:

  1. await die Aufgabe, so dass async wachsen.

async und await werden natürlich nach oben durch Ihre Code-Basis wachsen, bis sie Main erreichen, die nicht async sein können.

  1. Rufen Sie in Ihrer Main Methode GetAwaiter().GetResult() auf der "oberen" Aufgabe.

Blocking on asynchronous code is generally not a good idea, aber in einer Konsole App Main Methode auf eine einzige Aufgabe Sperrung ist eine Ausnahme von dieser Regel.

+0

Warum '.GetAwaiter(). GetResult()' anstelle von '.Wait()' oder '.Result'? Auch wenn es * einige * Fälle gibt, in denen es bequemer ist, erscheint es in einem * Los * von SO-Fragen –

+0

Weil 'Wait' und' Result' Exceptions in eine 'AggregateException' umbrechen, kompliziere Fehlerbehandlungscode. 'GetAwaiter(). GetResult()' macht das unnötige Wrapping nicht. –

+0

Das Problem ist, dass dies an vielen unnötigen Stellen auftaucht und den Code verkompliziert. Anstatt ein einzelner Aufruf am Ende einer Konsolenanwendung zu sein, erschien er in Webanwendungen, zB [this] (http: // stackoverflow.com/questions/43027847/code-nie-get-past-call-to-eventprocessorhost-registriereventprocessorasynclist), [this] (http://stackoverflow.com/questions/42947585/getasync-azure-call-no-result/42949748 # 42949748) und [dies] (http://stackoverflow.com/questions/42883020/get-token-from-oauth2-middleware) –