15

正如我在几个编码示例中看到的那样,以及我可以从这个SO 问题中理解的内容,我应该能够从 TaskCompletionSource 返回一个非泛型任务

(i.e., Return Task and not Task<TResult> from the method UploadFilesAsync) 

然而下面的代码:

public async Task UploadFilesAsync(string fileAPath, string fileBPath)
{
   var tcs = new TaskCompletionSource<Object>();

   //logic to process files

   try
   {
      await Task.WhenAll(uploadFileAAsync(fileAPath), 
                         uploadFileBAsync(fileBPath));
      tcs.TrySetResult(null);
   }
   catch (Exception e)
   {
      tcs.SetException(e);
   }
   finally
   {
      //logic to clean up files
   }
   return tcs.Task;
}

产生以下语法错误

'UploadFilesAsync(string, string)' is an async method that returns 'Task', 
a return keyword must not be followed by an object expression. 
Did you intend to return 'Task<T>'?

我的目标是 .NET 4.5。我知道它可以返回 Task(of object) 但这会使 API 感觉“脏”。是返回 Task(of object) 还是可以返回 Task (代码中显示的非泛型)的首选做法?

4

2 回答 2

25

我知道它可以返回 Task(of object)

好吧,那不会像您期望的那样。

问题是您正试图返回一个任务......并且异步方法会自动将返回值包装在另一个任务中。老实说,目前还不清楚你为什么在这里使用异步方法。为什么不直接写这个:

public Task UploadFilesAsync(string fileAPath, string fileBPath)
{
    return Task.WhenAll(uploadFileAAsync(fileAPath), uploadFileBAsync(fileBPath));
}

这不是你想要的吗?您只想要一个在两个“子操作”都完成时完成的任务,对吗?这正是Task.WhenAll返回的结果。您的方法仍然是非阻塞的 - 它不会等到操作完成后才返回。只是您使用的Task.WhenAll是非阻塞的事实来实现这一点,而不是异步方法。

编辑:请注意,如果您还想在该方法中执行其他操作,则可以在不使用TaskCompletionSource自己的情况下将其设为异步方法:

public async Task UploadFilesAsync(string fileAPath, string fileBPath)
{
    // Upload the files
    await Task.WhenAll(uploadFileAAsync(fileAPath), uploadFileBAsync(fileBPath));
    await SomethingElseAsync();
    MaybeDoSomethingCheap();
}

请注意,即使这里的 async 方法返回Task,您也没有返回值 - async/await 机器会为您处理所有这些,返回一个将在完成时MaybeDoSomethingCheap()完成的任务,或者如果抛出异常则返回错误。

于 2013-04-26T06:22:43.043 回答
2

据我所知,Task在使用TaskCompletionSource<T>.

通常我更喜欢在这些情况下返回一个Task<bool>类型对象。但是你是对的,如果函数的返回值不可用,则返回泛型类型对象是没有意义的。

但实际上您不需要创建 a,TaskCompletionSource因为您await在函数内部有一个关键字。TaskCompletionSource通常用于将同步函数转换为异步函数。由于您已经在调用异步函数(实际上这似乎是唯一的功能),因此您不需要创建TaskCompletionSource.

public async Task UploadFilesAsync(string fileAPath, string fileBPath)
{
        return await Task.WhenAll(uploadFileAAsync(fileAPath), uploadFileBAsync(fileBPath));
}
于 2013-04-26T06:25:18.637 回答