我被宠坏了异步/的await!现在挣扎问心无愧明确任务延续 [英] I've been spoiled by async/await! Now struggling wth explicit Task continuations

查看:317
本文介绍了我被宠坏了异步/的await!现在挣扎问心无愧明确任务延续的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

修改(验收后)

这可能不会立即显现,但@ Servy的答案是不需要展开下MonoDroid的自定义实现正确的它绝对不会。

It might not be immediately apparent but @Servy's answer is correct without needing a custom implementation of Unwrap under monodroid - in my comments I said it didn't exist, but it definitely does.

编辑完

我写了一堆使用REST风格的Web服务应用程序,尽管想我知道如何正确地使用任务事实证明,我不知道。该方案是我对Windows应用商店实现code - 使用异步/的await ,我需要实现近乎相同的东西MonoDroid的 - 这不有(如果没有一些黑客建立,我不希望使用)。

I'm writing a bunch of apps that use our RESTful web services and, despite thinking I know how to use tasks properly it turns out I don't. The scenario is that I have code implemented for Windows Store - using async/await and I need to implement something near-identical for MonoDroid - which doesn't have that (without some build hacks that I don't want to use).

我归结了问题,这个问题一组简单的获取一个整数异步,那么,在延续,发射另一个异步任务,轮流从该整数建立一个字符串的任务。在C#5,这将是:

I've boiled down the problem for this question to a simple set of tasks for getting an integer asynchronously, then, in the continuation, firing another asynchronous task that turns a string built from that integer. In C#5 this would be:

注 - 当然我用 Task.FromResult< T> 在这里发生的实际异步code的

Note - of course I'm using Task.FromResult<T> here in place of actual async code

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());
}

要将此转换为基于延续的模式我尝试这样做:

To convert this to a continuation-based pattern I tried this:

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 方法返回一个任务&LT;串&GT; 这意味着延续最终返回任务&LT;任务&LT;串&GT;&GT; ,而不是任务&LT;字符串方式&gt;

However, this isn't correct because the GetStringFromIntAsync method returns a Task<string> meaning that the continuation ends up returning a Task<Task<string>> instead of a Task<string>.

我发现,等待明确的 GetStringFromIntAsync 方法确实可行,但是:

I've found that explicitly waiting on the GetStringFromIntAsync method does work, however:

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

问题是,虽然 - 这是正确的方式做到这一点 - 我不能回到某种形式的延续,来电者然后等待上

The question is, though - is that the right way to do it - can I not return a continuation of some sort that the caller then waits on?

我用任务相当多的 - 而不是不同类型的一起类似这样的连锁任务(异步 / 除非等待课程) - 和感觉有点像我会疯了这里 - 所以任何帮助是极大的AP preciated

I have used tasks quite a bit - but not to chain tasks of different types together like this (except with async/await of course) - and feel a bit like I'm going mad here - so any help is greatly appreciated.

推荐答案

所以,首先,你非异步/等待第二个和第三个实现imlementations是当你有异步/等待你应该做的事情,甚至。使用它增加了什么,除了一点不必要的开销。

So, first off, your non-async/await imlementations of the second and third implementations is what you should do even when you have async/await. Using it adds nothing except a bit of unneeded overhead.

对于第一种情况,不,你不希望使用等待。这会阻碍,而不是允许其返回到池中的线程。您只需拆开包装任务,并得到它的内部任务。您可以使用展开方法来做到这一点:

As for the first case, no, you don't want to use Wait. That will block the thread instead of allowing it to be returned to the pool. You simply need to unwrap the task and get it's inner task. You can use the Unwrap method to do that:

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

下面是,如果一个不是提供给你,你可以使用展开功能。

Here is an Unwrap function that you can use if one is not available to you.

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;
}

这篇关于我被宠坏了异步/的await!现在挣扎问心无愧明确任务延续的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆