9

编辑(接受后)

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

结束编辑

我正在编写一堆使用我们的 RESTful Web 服务的应用程序,尽管我认为我知道如何正确使用任务,但事实证明我不知道。场景是我为 Windows Store 实现了代码 - 使用async/await并且我需要为 MonoDroid 实现几乎相同的东西 - 它没有(没有一些我不想使用的构建黑客)。

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

注意 - 当然我在Task.FromResult<T>这里使用的是实际的异步代码

private async Task<string> GetStringAsync()
{
    return await GetStringFromIntAsync(await GetIntAsync());
}

private async Task<int> GetIntAsync()
{
    return await Task.FromResult(10);
}

private async Task<string> GetStringFromIntAsync(int value)
{
    return await Task.FromResult(value.ToString());
}

要将其转换为基于延续的模式,我尝试了以下操作:

private Task<string> GetStringAsync()
{
    //error on this line
    return GetIntAsync().ContinueWith(t => GetStringFromIntAsync(t.Result));
}

private Task<int> GetIntAsync()
{
    return Task.FromResult(10);
}

private Task<string> GetStringFromIntAsync(int value)
{
    return Task.FromResult(value.ToString());
}

但是,这是不正确的,因为该GetStringFromIntAsync方法返回的Task<string>意思是延续最终返回 aTask<Task<string>>而不是 a Task<string>

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

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

但是,问题是-这是正确的方法-我不能返回调用者然后等待的某种延续吗?

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

4

3 回答 3

5

因此,首先,即使您有 async/await,您也应该执行第二个和第三个实现的非 async/await 实现。使用它只会增加一些不必要的开销。

至于第一种情况,不,你不想使用Wait. 这将阻塞线程而不是允许它返回到池中。您只需要解开任务并获取它的内部任务。您可以使用该Unwrap方法来做到这一点:

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

如果您没有可用的Unwrap功能,可以使用以下功能。

public static Task<T> Unwrap<T>(this Task<Task<T>> task)
{
    var tcs = new TaskCompletionSource<T>();

    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;
}
于 2013-01-18T16:07:48.437 回答
0

对于完全支持的方法,最好等待 MonoDroid 的官方异步/等待支持 - Xamarin 表示这“即将推出” - 今年上半年。

然而,如果你感觉更冒险......那么至少有几个人已经设法让 async/await 在 MonoDroid 中工作:

于 2013-01-19T12:18:00.990 回答
-1

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

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

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

于 2013-01-18T16:10:25.937 回答