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

我目前正在尝试将相当数量的现有同步代码移植到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;
        }
    }
}

MvvmCross WinRT ExtensionMethods开始 – 使用与IAsyncAction类似的方法

这些包装器似乎有效 – 它们允许我在同步代码中使用Async方法,如:

public IEnumerable<string> GetFilesIn(string folderPath)
    {
        var folder = StorageFolder.GetFolderFromPathAsync(ToFullPath(folderPath)).Await();
        var files = folder.GetFilesAsync().Await();
        return files.Select(x => x.Name);
    }

我知道这并不是真正符合WinRT的精神;但我希望这些方法通常只能在后台线程上调用;我写这篇文章的目的是让我的代码跨平台兼容 – 包括那些尚未支持await-async的平台和/或尚未准备好跳转的开发人员.

所以……问题是:使用这种类型的代码我运行的风险是什么?

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

解决方法

首先,我认为您的方法可以改写为:
public static TResult Await<TResult>(this IAsyncoperation<TResult> operation)
{
    return operation.AsTask().Result;
}

如果任务尚未完成,则调用结果将同步等待.如果失败,它将抛出AgreggateException.我认为像你一样抛出InnerException是个坏主意,因为它会覆盖异常的堆栈跟踪.

关于你的实际问题,我认为使用Wait()和异步代码的最大危险是死锁.如果你在UI线程上启动一些内部使用await的操作,然后在同一个线程上使用Wait()等待它,你将遇到死锁.

如果你没有在UI线程上等待,那么这并不重要,但如果可能的话,你仍然应该避免它,因为它违背了整个异步的想法.

相关文章

最近看了一下学习资料,感觉进制转换其实还是挺有意思的,尤...
/*HashSet 基本操作 * --set:元素是无序的,存入和取出顺序不...
/*list 基本操作 * * List a=new List(); * 增 * a.add(inde...
/* * 内部类 * */ 1 class OutClass{ 2 //定义外部类的成员变...
集合的操作Iterator、Collection、Set和HashSet关系Iterator...
接口中常量的修饰关键字:public,static,final(常量)函数...