2017-03-29 20 views
0

当我运行这段代码一切正常:异步恭候等效

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

我想更新该代码使用异步/等待。我试图这样做:

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

...但它不工作。很显然,我正在做一些调整。它确实调用了RunTask方法,并执行了前两行罚款,但它只是结束,我似乎无法捕捉TaskRun方法或上面的代码中的异常。我在输出窗口中看到的所有内容都是“程序已退出,代码为0(0x0)”。

如果那里的专家能够指出我做错了什么,或者给我一些关于如何捕捉异常并处理它的建议,我将非常感激。

此外,如果你觉得我错过了任何重要的细节,请问我会更新我的问题。

通常我会说,如果它的工作不解决它,但在这种情况下,我试图重新架构一点,以允许一些增强,所以我在这里。

+3

我注意到的第一件事,避免使用'async void'签名。使用'async Task'来代替主叫方。唯一的例外是WPF和WinForms应用程序中的事件处理程序。 – Igor

+6

'await'与'Wait'不一样。你的原始代码是同步的('WaitOne'),所以它不适合转换为'async/await'。 –

+3

1)将'async void'改为'async Task'。 2)“等待”任务,允许“异步”增长。 3)在你的'Main'方法中,在“顶部”任务中调用'GetAwaiter()。GetResult()'。 –

回答

3
  1. 变化async void变为async Task。请参阅我的文章async best practices了解更多信息。

完成此操作后,异步消耗它:

  • await任务,让async增长。
  • asyncawait自然会通过你的代码库向上生长,直到他们达到Main,从而无法async

    1. 在您的Main方法中,请在“top”任务上调用GetAwaiter().GetResult()

    Blocking on asynchronous code is generally not a good idea,但在控制台应用程序的Main方法中阻止单个任务是该规则的例外。

    +0

    为什么'.GetAwaiter()。GetResult()'而不是'.Wait()'或'.Result'?尽管可能会有一些更方便的情况,但它出现在许多SO问题中。 –

    +0

    因为Wait和Result在'AggregateException'中包装了异常,所以错误处理代码变得复杂了。 'GetAwaiter()。GetResult()'不会做不必要的包装。 –

    +0

    问题是,这已经开始出现在很多不需要的地方,使代码复杂化。它不是在控制台应用程序结束时进行单一调用,而是开始出现在Web应用程序中,例如[this](http:// stackoverflow。com/questions/43027847/code-never-get-past-call-to-eventprocessorhost -registereventprocessorasynclist),[this](http://stackoverflow.com/questions/42947585/getasync-azure-call-no-result/42949748 #42949748)和[this](http://stackoverflow.com/questions/42883020/get-token-from-oauth2-middleware) –