c# - 我被 async/await 宠坏了!现在正在为明确的任务延续而苦苦挣扎

标签 c# multithreading xamarin.android task-parallel-library async-await

编辑(接受后)

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

结束编辑

我正在编写一堆使用我们的 RESTful 网络服务的应用程序,尽管我认为我知道如何正确使用任务,但事实证明我不知道。场景是我为 Windows 应用商店实现了代码 - 使用 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>这意味着延续最终会返回一个 Task<Task<string>>而不是 Task<string> .

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

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

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

我已经使用了很多任务 - 但不是像这样将不同类型的任务链接在一起(当然除了 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;
}

关于c# - 我被 async/await 宠坏了!现在正在为明确的任务延续而苦苦挣扎,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14402773/

相关文章:

c# - 使用 DateTime.Now 插入值时 SqlDateTime 溢出

android - Xamarin Android 使用 GetExternalFilesDir() 获取 privateExternalStorage

xamarin.android - 如何在Xamarin Android中将状态栏和工具栏与渐变结合在一起

c# - 如何在不中断用户体验的情况下在后台轮询 webapi 请求?

c# - 如何使用 Facebook 取消授权回调

c# - 状态码不成功时无法读取HttpResponseMessage内容

c# - 传输数据的 Symbol.WPAN.Bluetooth 示例

c# - WPF DataGrid 和多线程

java - 使用ReentrantLock代替synchronized来提高性能

c# - 等待 WebBrowser ajax 内容