在.net framework 4.5 中,所有异步操作的系统函数返回值为一般都是Task 或Task<TResult> ,但在WinRT中,所有的系统函数异步操作都源自于一个接口IAsyncInfo,
public interface IAsyncInfo
{
Exception ErrorCode { get; }
uint Id { get; }
AsyncStatus Status { get; }
void Cancel();
void Close();
}
从这个接口上来看,它提供了取消和关闭任务的功能,并且能查看异步操作的执行状态,除了Status函数外,其它几个接口和TAP模式下的异步操作并没有直接关系,并且缺少await所需的GetResult()和OnCompleted()接口或能实现其功能的等价接口。也就是说,这个接口是不支持await的,对IAsyncInfo调用await会报编译错误。
虽然IAsyncInfo接口并本身不支持异步功能,实际上实际上我们使用的是它的四个子类,他们提供了GetResult()和OnCompleted()接口的等价声明:
public interface IAsyncAction : IAsyncInfo
{
AsyncActionCompletedHandler Completed { get; set; }
void GetResults();
}
public interface IAsyncOperation<TResult> : IAsyncInfo
{
AsyncOperationCompletedHandler<TResult> Completed { get; set; }
TResult GetResults();
}
public interface IAsyncActionWithProgress<TProgress> : IAsyncInfo
{
AsyncActionWithProgressCompletedHandler<TProgress> Completed { get; set; }
AsyncActionProgressHandler<TProgress> Progress { get; set; }
void GetResults();
}
public interface IAsyncOperationWithProgress<TResult, TProgress> : IAsyncInfo
{
AsyncOperationWithProgressCompletedHandler<TResult, TProgress> Completed { get; set; }
AsyncOperationProgressHandler<TResult, TProgress> Progress { get; set; }
TResult GetResults();
}
从它们的声明来看,IAsyncAction等价于不带返回值的异步任务Task,IAsyncOperation<TResult>等价带返回值的异步任务Task<T>。另外,还提供了两个带进度报告的版本:IAsyncActionWithProgress和IAsyncOperationWithProgress。
虽然这四个接口本身都没有声明GetAwaiter(),但WinRT类库WindowsRuntimeSystemExtensions中定义了相应的GetAwaiter扩展函数,因此它们是支持await操作的,返回值从其接口GetResults()中获取。
public static class WindowsRuntimeSystemExtensions
{
public static TaskAwaiter GetAwaiter(this IAsyncAction source);
public static TaskAwaiter<TResult> GetAwaiter<TResult>(this IAsyncOperation<TResult> source);
public static TaskAwaiter GetAwaiter<TProgress>(this IAsyncActionWithProgress<TProgress> source);
public static TaskAwaiter<TResult> GetAwaiter<TResult, TProgress>(this IAsyncOperationWithProgress<TResult, TProgress> source);
}
在使用await操作时,我们往往还需要通过async关键字来配套使用,将多个await操作来重新封装成一个新的异步函数。在.net 4.5中,我们往往这么使用:
public async Task AsyncOperation()
{
await ...
return;
}
由于WinRT的异步返回值是IAsyncInfo,那么我们是不是该把Task换成等价的IAsyncOperation呢?
public async IAsyncAction AsyncOperation()
{
await ...
return;
}
实际上,当我们这么写时,会得倒一个"异步方法的返回类型必须为 void、Task 或 Task<T>"的编译错误。也就是说,在WinRT中,异步操作模型和.Net 4.5是一致的,本身还是基于Task的异步编程。
既然Task仍然是WinRT的异步编程的一等公民,那为什么还要提供一个IAsyncInfo呢?让我们再回头看看IAsyncInfo接口,发现他具有Task所不支持的两个接口:Cancel和Close。
从上可以看出:IAsyncInfo(的四个子接口)其实是个Task的增强版(支持Cancel和Close),WinRT系统的异步函数返回值提供的功能更加强大。
既然IAsyncInfo比Task更加强大,其自然也是可以转换成Task的,在WindowsRuntimeSystemExtensions类中就提供了扩展函数AsTask()实现把IAsyncInfo(的四个子类)转换为Task,从而使用Task的各个功能函数,使之更加强大,例如:
public static TaskAwaiter GetAwaiter(this IAsyncAction source)
{
return source.AsTask().GetAwaiter();
}
await SomeMethodAsync().AsTask().ConfigureAwait(false);
CancellationToken token = ...;
await SomeMethodAsync().AsTask(token);
IProgress<TProgress> progress = ...;
await SomeMethodAsync().AsTask(progress);
Task firstCompleted = await Task.WhenAny(
SomeMethod1Async().AsTask(),
SomeMethod2Async().AsTask(),
SomeMethod3Async().AsTask());
既然知道了如何使用IAsyncInfo,除了系统自带的函数,我们如何创建自己的IAsyncInfo呢?常用方法有如下两种:
以上只是对WinRT的异步操作进行了一个简单的介绍,如果想更加详细的了解相关知识,请参考MSDN文章:深入探究 WinRT 和 await,将 .NET 任务作为 WinRT 异步操作公开。