我被异步/等待宠坏了! 现在正在努力与明确的任务延续

编辑(接受后)

它可能不会立即显现,但@Servy的答案是正确的,而不需要在monodroid下自定义实现Unwrap – 在我的评论中我说它不存在,但它确实存在。

结束编辑

我正在编写一堆使用我们的RESTful Web服务的应用程序,尽管我认为我知道如何正确使用任务但事实并非如此。 场景是我已经为Windows Store实现了代码 – 使用async/await我需要为MonoDroid实现几乎相同的东西 – 没有那个(没有我不想使用的构建攻击)。

我已经将这个问题的问题归结为一组简单的异步获取整数的任务,然后,在继续中,触发另一个异步任务,转换从该整数构建的字符串。 在C#5中,这将是:

注意 – 当然我在这里使用Task.FromResult代替实际的异步代码

 private async Task GetStringAsync() { return await GetStringFromIntAsync(await GetIntAsync()); } private async Task GetIntAsync() { return await Task.FromResult(10); } private async Task GetStringFromIntAsync(int value) { return await Task.FromResult(value.ToString()); } 

要将此转换为基于延续的模式,我试过这个:

 private Task GetStringAsync() { //error on this line return GetIntAsync().ContinueWith(t => GetStringFromIntAsync(t.Result)); } private Task GetIntAsync() { return Task.FromResult(10); } private Task GetStringFromIntAsync(int value) { return Task.FromResult(value.ToString()); } 

但是,这是不正确的,因为GetStringFromIntAsync方法返回一个Task这意味着continuation最终返回Task<Task>而不是Task

我发现显式等待GetStringFromIntAsync方法确实有效,但是:

 private Task GetStringAsync() { return GetIntAsync().ContinueWith(t => { var nested = GetStringFromIntAsync(t.Result); nested.Wait(); return nested.Result; }); } 

问题是,尽管 – 这是正确的方法 – 我是否可以不返回呼叫者等待的某种延续?

我已经使用了相当多的任务 – 但不是像这样将不同类型的任务链接在一起(当然除了async / await之外) – 感觉有点像我在这里生气 – 所以任何帮助都非常感激。

所以,首先,即使你有异步/等待,你的第二个和第三个实现的非异步/等待的重复是你应该做的。 除了一些不必要的开销外,使用它不会增加任何内容。

至于第一种情况,不,你不想使用Wait 。 这将阻止线程而不是允许它返回池。 您只需要解开任务并获得它的内部任务。 您可以使用Unwrap方法执行此操作:

 private Task GetStringAsync() { return GetIntAsync() .ContinueWith(t => GetStringFromIntAsync(t.Result)) .Unwrap(); } 

这是一个Unwrapfunction,如果您无法使用,可以使用它。

 public static Task Unwrap(this Task> task) { var tcs = new TaskCompletionSource(); task.ContinueWith(t => { t.Result.ContinueWith(innerT => tcs.SetResult(innerT.Result) , TaskContinuationOptions.OnlyOnRanToCompletion); t.Result.ContinueWith(innerT => tcs.SetCanceled() , TaskContinuationOptions.OnlyOnCanceled); t.Result.ContinueWith(innerT => tcs.SetException(innerT.Exception.InnerExceptions) , TaskContinuationOptions.OnlyOnRanToCompletion); } , TaskContinuationOptions.OnlyOnRanToCompletion); task.ContinueWith(t => tcs.SetCanceled() , TaskContinuationOptions.OnlyOnCanceled); task.ContinueWith(t => tcs.SetException(t.Exception.InnerExceptions) , TaskContinuationOptions.OnlyOnFaulted); return tcs.Task; } 

对于完全支持的方法,最好等待官方的异步/等待支持MonoDroid – Xamarin已经说过“即将推出” – 今年上半年。

但是,如果你感觉更冒险……那么至少有几个人设法让异步/等待在MonoDroid中工作:

这就是我在.net 4.0(VS 2010)中处理异步任务所做的工作。 有些人说你不需要调用task.Wait(); 和其他人说过,是的,你确实需要调用task.Wait(); 我认为区别在于task.Wait()是否隐含/封装在task.Result属性中。

我坚持使用更明确的方法来调用task.Wait();

这将阻止,直到调用完成,但如果您不使用4.5,我不确定还有哪些其他选项可用。