将IAsyncOperation转换为Task,如何正确实现AsTask扩展方法
现有实现的问题
你当前编写的AsTask扩展方法不符合异步规范,存在两个核心问题:
- 直接调用
IAsyncOperation<TResult>.GetResults()时,若WinRT异步操作还未完成,会直接抛出异常,且该调用是同步阻塞逻辑,完全失去异步非阻塞的优势 Task.FromResult仅能包装已完成的同步结果,没有实现对WinRT异步操作的生命周期监听逻辑
正确的实现方案
方案1:优先使用官方扩展(推荐)
如果你的项目是UWP、WinUI 3、.NET MAUI Windows平台等支持WinRT互操作的项目,不需要自行实现AsTask方法,直接引用System.Runtime.WindowsRuntime程序集,微软官方已经提供了全功能的生产级AsTask扩展,支持取消令牌、进度回调等多种重载,稳定性远高于自定义实现。
方案2:自定义实现AsTask扩展
如果你必须自行实现,可参考如下基于TaskCompletionSource的标准实现:
using Windows.Foundation; public static class Helpers { public static Task<TResult> AsTask<TResult>(this IAsyncOperation<TResult> source) { if (source == null) throw new ArgumentNullException(nameof(source)); // 操作已完成时直接返回结果,避免额外分配 if (source.Status == AsyncStatus.Completed) { return Task.FromResult(source.GetResults()); } var completionSource = new TaskCompletionSource<TResult>(); source.Completed += (asyncOperation, status) => { try { switch (status) { case AsyncStatus.Completed: completionSource.TrySetResult(asyncOperation.GetResults()); break; case AsyncStatus.Canceled: completionSource.TrySetCanceled(); break; case AsyncStatus.Error: completionSource.TrySetException(asyncOperation.ErrorCode); break; } } catch (Exception ex) { completionSource.TrySetException(ex); } finally { asyncOperation.Close(); } }; return completionSource.Task; } }
该实现的核心逻辑是通过TaskCompletionSource封装异步操作的状态流转,监听WinRT异步操作的Completed事件,在操作结束后再对应设置Task的完成/取消/异常状态,全程不会阻塞调用线程,同时释放IAsyncOperation资源避免内存泄漏。
内容的提问来源于stack exchange,提问作者Mselmi Ali
相关产品推荐
相关产品推荐

