2016-06-14 219 views
1

只希望在C#中使用异步等待时有人可以清除返回类型。我明白你有三种返回类型:任务< T>,任务和无效。从试图了解这一点我已经读过你应该只在特殊情况下使用void(事件处理程序),如果你正在改变同步方法为异步方法,那么你应该将一个void关键字更改为任务。C#.NET异步等待返回类型

我的问题是我是否需要一个任务返回类型,即使代码是完全独立的,结果对延续无关紧要?举例来说,我使用异步方法将一些信息推送到Web服务。

我创建了一个小例子,以帮助解释:

private void CallingMethod() 
    { 
     AsyncMethod(); 
     AsyncTaskMethod(); // any difference between doing these? (not exc handling) 

     var task = AsyncTaskMethod(); // should I do anything with this task 
             // before I continue? Or is it simply 
             // just to show the user that it's async?? 


     // continue with unrelated code that doesnt require task or any code from above 
    } 

    private async void AsyncMethod() // is void okay? 
    { 
     await LongRunningMethod(); 

     // do other stuff 
    } 

    private async Task AsyncTaskMethod() // or should it be Task? 
    { 
     await LongRunningMethod(); 

     // do other stuff 
    } 

    private async Task LongRunningMethod() 
    { 
     // do long running code 
    } 

我的应用程序有像这样有很多方法:

private void BigMethod() 
    { 
     DoStuff(); 

     DoMoreStuff(); 

     AsyncMethod(); // is this right? Or should I have the task declaration too? 

     UnrelatedStuff(); 
    } 

    private async Task AsyncMethod() // should this return task? 
    { 
     var result = await GetUserId(); 

     if (result == null) 
      return; 

     MyUserId = result; 
    } 

    private async Task<int> GetUserId() 
    { 
     // do long running code 
     return 1; 
    } 

如果它是不明确的,通过各种手段只是说和我我会尽量整理一下。多谢你们。

编辑:

private void CallingMethod() 
    { 
     AsyncMethod(); 
    } 

    private async void AsyncMethod() 
    { 
     await LongRunningMethod(); 
    } 

    private async Task LongRunningMethod() 
    { 
     await Task.Run(() => 
     { 
      Thread.Sleep(4000); 
     }); 

     MessageBox.Show("Done!"); 
    } 

在响应于第一评论,上述CallingMethod不使用等待/异步和它高兴地睡4秒钟,而不锁定了GUI线程,然后弹出的消息框。有什么问题?

+1

CallingMethod()应​​该使用'async'和'await'。没有这个问题就没有什么意义。 –

+0

请注意,“异步”与“parellel”不同:“await”行之后的代码在该行完成等待之前不会执行。 –

+0

它不必?请检查编辑 – Murphybro2

回答

1

您不能等待返回void的方法,而且其中一个主要原因是void返回异步方法的调用方无法捕获异步方法抛出的异常。尝试:

public void TryToCatchMethod() { 
    try { 
     MyAsyncMethod(); 
    } catch (Exception exception) { 
     //tha catch is never called 
     Debug.WriteLine(exception.ToString()); 
    } 
    } 
    public async void MyAsyncMethod() { 
    throw new Exception(); 
    } 
+0

好吧,谢谢,这很棒。那么最佳选择是什么?用Task替换void?这样做会阻止程序崩溃的异常,但它似乎并没有被捕获? – Murphybro2

+0

将其替换为:public async Task MyAsyncMethod(){ throw new Exception(); }然后等待它,你会看到catch块如何被执行。 –

3

你不使用Task当一个方法返回void,但它的确是首选,有以下几个原因:

  1. 异步方法返回一个Task(或Task<T>)对返回的Task有例外,因此调用方法可以检查(当他们认为合适时)Task是否有故障。

  2. Async void方法都有各自的异常,直接扔在调用同步上下文,使得它几乎(因为你仍然可以使用全局异常处理程序,但这是不可维护的大型应用程序)不可能来处理确定性对他们异常方式。

  3. 你基本上无法测试任何async void方法可能抛出一个异常

  4. async void方法假定当它们被调用方运行完成。这可能会引入许多问题(实际上,当您尝试将现有的库转换为异步时,事件处理程序会遇到很多问题:继续操作,获取第三方相对复杂的winforms库并尝试使异步事件处理程序异步,会看到它造成的破坏!)。

  5. 没有合理的方式确定何时async void方法已经完成(你可以让自己的SynchronizationContext,但是这件事情肯定是复杂的)

  6. 不能配置async void通话(你不能使用ConfigureAwait),所以继续上下文始终是调用者的同步上下文。

所以......

TL; DR:不使用async void,除非你无法避免它(即:与期待void签名事件处理程序)。这是有原因的。如果您不希望得到结果,请使用async Task

+0

好了,所以我有这样的代码: 公共无效TryToCatchMethod(){ 尝试 { MyAsyncMethod(); } catch(异常例外) { //暂时从未调用捕获 Debug.WriteLine(exception.ToString()); } } public async void MyAsyncMethod() { throw new Exception(); } 当引发异常时,应用程序崩溃,未处理的异常。那么我如何改变它来捕捉异常呢? – Murphybro2

+0

我对格式表示歉意,请参阅格式化版本的Radin Gospodinovs答案 – Murphybro2

+0

使async方法返回'Task',并让调用方法'await':[在此检查](https://dotnetfiddle.net/zU93YA )。使它*异步一路下降*(当我们在它,改变调用方法返回'任务'太) – Jcl