2013-04-26 66 views
12

正如我所看到的几个coding examples,还有,我可以从这个SO question明白我应该能够从TaskCompletionSource返回任务,而不是任务<TResult>从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。我知道它可以返回任务(对象),但这会让API感觉“脏”。返回任务(对象)还是有可能返回任务(代码中显示的非泛型)是否是首选实践?

回答

25

我知道它可以工作返回任务(目标)

好了,不会做你希望它是什么。

麻烦的是,你试图返回一个任务...和异步方法自动将返回值包装在另一个任务中。目前还不清楚为什么你在这里使用异步方法,说实话。为什么不写这个:

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 ,你没有返回值 - 异步/等待机制为你处理所有这些,返回一个当MaybeDoSomethingCheap()完成时将完成的任务,或者在抛出异常时返回错误。

+0

我必须解压缩文件,运行上传,然后删除解压后的文件。我希望上传运行异步,这就是为什么我将它们包装在taskcompletionsource中,或者我会按照您的建议完成。这是有道理的,异步包装在另一个任务中的回报(难怪用async/await看到一个工作示例很难)。谢谢! – 2013-04-26 06:27:58

+1

@JonathanHarrison:只是为了检查 - 你是否明白为什么你能按我的建议做,而且它仍然是异步的?我会补充一点,这可能会有所帮助... – 2013-04-26 06:38:24

+0

非常感谢您的编辑。这个概念最初没有点击过......非常美妙,async/await实际上处理了这样的异步无效方法。 – 2013-04-26 06:52:28

2

据我所知,在雇用TaskCompletionSource<T>时没有直接的方法返回Task对象。

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

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

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

感谢您的回应,你写的是有道理的。看到我对Jon Skeet的评论,为什么我使用了TaskCompletionSource。 – 2013-04-26 06:31:17