正如我在几个coding examples中看到的那样,以及我从这个SO question可以理解的东西,我应该能够从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(对象),但这会使API感觉“脏”。是首选返回Task(对象)还是可以返回Task(非泛型,如代码所示)?
答案 0 :(得分:25)
我知道它可以用来返回Task(对象)
嗯,这不符合你的预期。
问题在于您尝试返回任务...而异步方法会自动将返回值包装在另一个任务中。说实话,目前还不清楚为什么你在这里使用异步方法。为什么不写这个:
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();
}
请注意,即使此处的异步方法返回Task
,您也没有返回值 - async / await机器会为您处理所有这些,返回一个将在{{1}时完成的任务如果抛出异常,则已完成或出错。
答案 1 :(得分:2)
据我所知,使用Task
时无法直接返回TaskCompletionSource<T>
个对象。
通常我更喜欢在这些情况下返回Task<bool>
类型的对象。但你是对的,如果函数的返回值不可用,则返回泛型类型对象是没有意义的。
但实际上您不需要创建TaskCompletionSource
,因为函数内部有await
个关键字。 TaskCompletionSource
通常用于将同步函数转换为异步函数。由于您已经在调用异步函数(实际上这似乎是唯一的功能),因此您无需创建TaskCompletionSource
。
public async Task UploadFilesAsync(string fileAPath, string fileBPath)
{
return await Task.WhenAll(uploadFileAAsync(fileAPath), uploadFileBAsync(fileBPath));
}