.net 用Task.Wait()代码包装Async/Await IAsyncOperations有什么风险?

.net 用Task.Wait()代码包装Async/Await IAsyncOperations有什么风险?,.net,windows-runtime,async-await,c#-5.0,.net,Windows Runtime,Async Await,C# 5.0,我目前正在尝试将大量现有的同步代码移植到WinRT 作为其中的一部分,我遇到了现有代码的问题,这些代码期望某些操作是同步的,例如,对于文件I/O 为了使现有代码适应WinRT中的IAsyncOperation样式API,我使用了一种技术,用扩展方法包装IAsyncOperation,如: namespace Cirrious.MvvmCross.Plugins.File.WinRT { public static class WinRTExtensionMethods {

我目前正在尝试将大量现有的同步代码移植到WinRT

作为其中的一部分,我遇到了现有代码的问题,这些代码期望某些操作是同步的,例如,对于文件I/O

为了使现有代码适应WinRT中的IAsyncOperation样式API,我使用了一种技术,用扩展方法包装IAsyncOperation,如:

namespace Cirrious.MvvmCross.Plugins.File.WinRT
{
    public static class WinRTExtensionMethods
    {
        public static TResult Await<TResult>(this IAsyncOperation<TResult> operation)
        {
            var task = operation.AsTask();
            task.Wait();
            if (task.Exception != null)
            {
                // TODO - is this correct?
                throw task.Exception.InnerException;
            }

            return task.Result;
        }
    }
}
我明白这并不符合温特的精神;但是我希望这些方法通常只在后台线程上被调用;我写这篇文章的目的是使我的代码能够跨平台兼容,包括那些还不支持wait-async的平台和/或那些还没有准备好跳转的开发人员

所以。。。问题是:使用这种类型的代码会有什么风险


第二个问题是,有没有更好的方法可以实现文件I/O等领域的代码重用?

首先,我认为您的方法可以重写为:

public static TResult Await<TResult>(this IAsyncOperation<TResult> operation)
{
    return operation.AsTask().Result;
}
public static TResult Await(此IAsyncOperation操作)
{
返回操作.AsTask().Result;
}
如果任务尚未完成,则调用
Result
将同步等待。如果失败,它将抛出一个
agreegateException
。我认为像您这样抛出
InnerException
是个坏主意,因为它会覆盖异常的堆栈跟踪

关于您的实际问题,我认为将
Wait()
与异步代码一起使用的最大危险是死锁。如果在UI线程上启动内部使用
wait
的某个操作,然后在同一线程上使用
wait()
等待该操作,则会出现死锁


如果您没有在UI线程上执行
Wait()
ing,那么这一点就不那么重要了,但是如果可能,您仍然应该避免它,因为它违背了整个
async
思想。

有很多很好的理由不这样做。例如,见

但是如果您想这样做,请使用GetResults()方法,如下所示

public static TResult Await<TResult>(this IAsyncOperation<TResult> operation)
{
    try
    {
        return operation.GetResults();
    }
    finally
    {
        operation.Close();
    }
}  
public static TResult Await(此IAsyncOperation操作)
{
尝试
{
返回操作。GetResults();
}
最后
{
操作。关闭();
}
}  

正如svick提到的,将IAsyncOperation包装到任务中也很有效,但效率较低。

我终于要回答这个问题了

答案是你真的做不到

即使您尝试使用其他答案中建议的一些更干净的方法,如果您尝试在承诺不会阻塞的任何线程上运行代码,例如,如果您尝试在UI线程或线程池线程上运行代码,那么最终还是会遇到异常


所以。。。答案是,您只需重新构建遗留代码,使其在某种程度上是异步的

谢谢你的回答。关于异常问题,我试图让周围的代码期望出现FileNotFoundException之类的异常,但我真的不能期望它们处理AggregateException。不过,总的来说,我希望这是一个权宜之计——从长远来看,我要么重写API以使用基于动作的回调,要么在其他平台上也使用wait/async(当vs11/C#4.5推出测试版时,MonoTouch和MonoDroid将获得支持!)FWIW,his似乎更符合wait关键字,因为它会引发内部异常而不是聚合。我无法让它工作。我尝试了以下代码:var folder=ApplicationData.Current.LocalFolder;var items=folder.CreateItemQuery().GetItemsAsync().Await();并获取:GetResults中发生“System.InvalidOperationException”类型的异常。详细信息:在意外时间调用了方法。(HRESULT的异常:0x800000E)。AsTask()。结果有效。我也有同样的问题,这就是我找到这篇文章的原因。GetResults()不起作用,但AsTask()起作用。结果正常
public static TResult Await<TResult>(this IAsyncOperation<TResult> operation)
{
    try
    {
        return operation.GetResults();
    }
    finally
    {
        operation.Close();
    }
}