C# I';我被async/await搞坏了!现在正在与明确的任务继续进行斗争

C# I';我被async/await搞坏了!现在正在与明确的任务继续进行斗争,c#,multithreading,xamarin.android,task-parallel-library,async-await,C#,Multithreading,Xamarin.android,Task Parallel Library,Async Await,编辑(验收后) 这可能不是很明显,但是@Servy的答案是正确的,不需要monodroid下的Unwrap自定义实现——在我的评论中,我说它不存在,但它确实存在 结束编辑 我正在编写一系列使用RESTful web服务的应用程序,尽管我认为自己知道如何正确使用任务,但事实证明我不知道。这个场景是,我已经为Windows应用商店实现了代码——使用async/await,我需要为MonoDroid实现一些几乎相同的东西——这是没有的(没有一些我不想使用的构建技巧) 我已经将这个问题归结为一组简单的任

编辑(验收后)

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

结束编辑

我正在编写一系列使用RESTful web服务的应用程序,尽管我认为自己知道如何正确使用任务,但事实证明我不知道。这个场景是,我已经为Windows应用商店实现了代码——使用
async/await
,我需要为MonoDroid实现一些几乎相同的东西——这是没有的(没有一些我不想使用的构建技巧)

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

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

然而,问题是——这是正确的方法吗——我能不能不返回调用方等待的某种类型的延续


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

所以,首先,第二个和第三个实现的非异步/等待实现是您应该做的,即使您有异步/等待。使用它只会增加一点不必要的开销

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

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

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

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


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

对于完全支持的方法,可能最好等待MonoDroid的官方异步/等待支持-Xamarin说这很快就要到来了-今年上半年

然而,如果你觉得更冒险。。。然后,至少有几个人在MonoDroid中实现了异步/等待工作:

  • 使用“全单声道”——
  • 使用“Microsoft BCL”-参见Daniel Plaisted在BUILD上的演讲中的twittersearch示例和代码

是的,我理解你对第二种和第三种方法的意思-谢谢。在.NET4(Monodroid正在使用的)中,
Unwrap
的等价物是什么?@AndrasZoltan现在正在编写一个版本。Wowzers-太棒了,谢谢,我来试试。我刚刚浏览了真正的展开方法实现——但是您的更新看起来不错。非常感谢@AndrasZoltan在4.5中实现它要灵活得多。方法的主体是
返回等待任务大多数代码只是围绕异常处理/取消(这是
await
处理得很好的原因,这就是为什么它更短的原因)。如果忽略所有这些,它将归结为两个嵌套的
ContinueWith
调用,用于设置TCS的结果。。如果MonoDroid中没有它,我会感到惊讶,尽管这肯定是有可能的。
这将阻止调用,直到调用完成,但我不确定如果您不使用4.5,还有哪些其他选项可用。
好吧,鉴于这正是OP要求的,如果您不知道,您可能不应该回答。请记住,异步特性不添加运行时支持,它们都是使用4.0中已有的工具构建的,只需很少的代码即可实现。
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());
}
private Task<string> GetStringAsync()
{
    return GetIntAsync().ContinueWith(t =>
    {
        var nested = GetStringFromIntAsync(t.Result);
        nested.Wait();
        return nested.Result;
    });
}
private Task<string> GetStringAsync()
{
    return GetIntAsync()
        .ContinueWith(t => GetStringFromIntAsync(t.Result))
        .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;
}