7

我目前正在尝试将大量现有同步代码移植到 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 等领域的代码重用?

4

3 回答 3

3

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

public static TResult Await<TResult>(this IAsyncOperation<TResult> operation)
{
    return operation.AsTask().Result;
}

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

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

如果您不在 UI 线程上,这并不重要Wait(),但您仍应尽可能避免它,因为它与整个async想法背道而驰。

于 2012-05-20T00:05:01.017 回答
2

有很多充分的理由不这样做。参见例如http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx

但是如果你想这样做,使用 GetResults() 方法如下

public static TResult Await<TResult>(this IAsyncOperation<TResult> operation)
{
    try
    {
        return operation.GetResults();
    }
    finally
    {
        operation.Close();
    }
}  

正如 svick 所提到的,将 IAsyncOperation 包装在任务中也可以,但效率较低。

于 2012-05-20T21:06:08.530 回答
2

我终于来回答这个问题了......

答案是你真的做不到。

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

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

于 2012-10-09T15:21:27.320 回答