简体   繁体   English

返回任务而不是任务 <TResult> 来自TaskCompletionSource

[英]Return Task instead of Task<TResult> from TaskCompletionSource

As I have seen in several coding examples , as well as, what I can understand from this SO question I should be able to return a non-generic Task from TaskCompletionSource 正如我在几个编码示例中看到的,以及从这个SO问题我可以理解的,我应该能够从TaskCompletionSource返回一个非泛型任务

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

Yet the following code: 但是以下代码:

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

Produces the following syntax error 产生以下语法错误

'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>'?

I am targeting .NET 4.5. 我的目标是.NET 4.5。 I know it can work to return Task(of object) but that makes the API feel "dirty". 我知道它可以返回Task(对象),但这会使API感觉“脏”。 Is it preferred practice to return Task(of object) or is it possible to return Task (non-generic as shown in the code)? 是首选返回Task(对象)还是可以返回Task(非泛型,如代码所示)?

I know it can work to return Task(of object) 我知道它可以工作返回Task(对象)

Well, that won't do what you expect it to. 那么,这不会达到你的预期。

The trouble is that you're trying to return a task... and an async method automatically wraps the return value in another task. 麻烦的是你正在尝试返回一个任务......而异步方法会自动将返回值包装在另一个任务中。 It's not clear why you're using an async method at all here, to be honest. 说实话,目前还不清楚为什么你在这里使用异步方法。 Why not just write this: 为什么不写这个:

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

Does that not do what you want? 那不是你想做的吗? You just want a task which completes when both of the "suboperations" have completed, right? 你只想要一个在两个“子操作”完成时完成的任务,对吧? That's exactly what Task.WhenAll returns. 这正是Task.WhenAll返回的内容。 Your method is still non-blocking - it won't wait until the operations have completed before it returns. 您的方法仍然是非阻塞的 - 它不会等到操作完成后再返回。 It's just that you're using the fact that Task.WhenAll is non-blocking to achieve that, instead of an async method. 只是你正在使用Task.WhenAll是非阻塞的事实来实现它,而不是异步方法。

EDIT: Note that if you wanted to do something else in that method as well, you could make it an async method without using TaskCompletionSource yourself: 编辑:请注意,如果您想在该方法中执行其他操作,则可以在不使用TaskCompletionSource情况下将其设置为异步方法:

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

Note that even though the async method here returns Task , you don't have a return value - the async/await machinery handles all of that for you, returning a task which will complete when MaybeDoSomethingCheap() has finished, or fault if an exception is thrown. 请注意,即使此处的async方法返回Task ,您也没有返回值 - async / await机制为您处理所有这些,返回一个任务,该任务将在MaybeDoSomethingCheap()完成时完成,或者如果异常则返回错误被扔了。

As far as I know there is no direct way to return a Task object when employing TaskCompletionSource<T> . 据我所知,在使用TaskCompletionSource<T>时没有直接返回Task对象的方法。

Generally I prefer to return a Task<bool> type object at these situations. 通常我更喜欢在这些情况下返回Task<bool>类型对象。 But you are right that, returning a generic type object makes no sense if return values of the function is not usable. 但你是对的,如果函数的返回值不可用,则返回泛型类型对象是没有意义的。

But in fact you do not need to create a TaskCompletionSource since you have an await keyword inside the function. 但实际上你不需要创建一个TaskCompletionSource因为你在函数中有一个await关键字。 TaskCompletionSource is generally used to convert an synchronous function to an asynchronous one. TaskCompletionSource通常用于将同步函数转换为异步函数。 Since you are already calling an asynchronous function (and in fact this seems as the only functionality) you do not need to create a TaskCompletionSource . 由于您已经在调用异步函数(实际上这似乎是唯一的功能),因此您无需创建TaskCompletionSource

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM