C# I';我被async/await搞坏了!现在正在与明确的任务继续进行斗争
编辑(验收后) 这可能不是很明显,但是@Servy的答案是正确的,不需要monodroid下的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实现一些几乎相同的东西——这是没有的(没有一些我不想使用的构建技巧) 我已经将这个问题归结为一组简单的任
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;
}