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

And*_*tan 9 c# multithreading task-parallel-library xamarin.android async-await

编辑(接受后)

它可能不会立即显现,但@ 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());
}
Run Code Online (Sandbox Code Playgroud)

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

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());
}
Run Code Online (Sandbox Code Playgroud)

但是,这是不正确的,因为该GetStringFromIntAsync方法返回一个Task<string>含义,即延续最终返回Task<Task<string>>而不是a Task<string>.

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

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

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

我用任务相当多的-而不是不同类型的连锁任务,这样在一起(除了async/ await课程) -感觉有点像,我要疯了这里-所以任何帮助是极大的赞赏.

Ser*_*rvy 5

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

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

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

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;
}
Run Code Online (Sandbox Code Playgroud)