From: http://www.cnblogs.com/TianFang/archive/2012/09/21/2696769.html
可以用于await运算符的对象要求如下:
-
有一个GetAwaiter()方法或扩展方法,它返回一个实现了INotifyCompletion接口的awaiter对象(或结构)
-
返回的awaiter对象(或结构)要求实现如下方法:
-
void OnCompleted(Action continuation)
-
bool IsCompleted {get; }
-
TResultGetResult()// TResult也可以是 void类型
下面我就简单的介绍一下await运算符是如何实现异步操作的。
例如,对于如下代码
var j = await 3;
DoContinue(j);
在编译的时候会被编译器翻译为类似如下流程的代码(注:这个只是功能类似的简化流程示例,实际并非如此)。
var awaiter = 3.GetAwaiter();
var continuation = new Action(() =>
{
var j = awaiter.GetResult();
DoContinue(j);
});
if (awaiter.IsCompleted)
continuation();
else
awaiter.OnCompleted(continuation);
有了这个基础,我们就可以对一个int型的变量实现await操作了:
class Program
{
staticvoid Main(string[] args)
{
Test();
Console.ReadLine();
}
async static void Test()
{
var j = await 3;
Console.WriteLine(j);
}
}
class MyAwaiter : System.Runtime.CompilerServices.INotifyCompletion
{
public bool IsCompleted {get {returnfalse; } }
public void OnCompleted(Action continuation)
{
Console.WriteLine("OnCompleted");
ThreadPool.QueueUserWorkItem(_ =>
{
Thread.Sleep(1000);
this.result = 300;
continuation();
});
}
int result;
public int GetResult()
{
Console.WriteLine("GetResult");
return result;
}
}
static class Extend
{
public static MyAwaiter GetAwaiter(thisint i)
{
return new MyAwaiter();
}
}
这样我们就能看出await是如何实现call/cc式的异步操作了:
-
编译器把后续操作封装为一个Action对象continuation,传入awaiter的OnCompleted函数并执行。
-
awaiter在OnCompleted函数中执行异步操作,并在异步操作完成后(一般是异步调用的回调函数)执行continuation操作。
-
continuation操作的第一步就是调用awaiter.GetResult()获取异步操作的返回值,并继续执行后续操作。
看到这里,相信大家对await的机制已经有了简单的认识,也就不难理解为什么AsyncTargetingPack能使得.net 4.0程序也支持await操作了——该库在AsyncCompatLibExtensions类中对Task类提供了GetAwaiter扩展函数而已。
using System; using System.Runtime.CompilerServices; using System.Threading; using System.Threading.Tasks; using System.Windows.Forms; namespace WindowsFormsApplication2 { public partial class Form1 : Form { public Form1() { InitializeComponent(); DoSomething(); } public async Task DoSomething() { int test = 3; await Sleep(); MessageBox.Show("Woke up!" + test.ToString()); } internal MyTask Sleep() { return new MyTask(); } public class MyTask { public MyAwaiter GetAwaiter() { return new MyAwaiter(); } } public class MyAwaiter : INotifyCompletion { public MyAwaiter() { } public void OnCompleted(Action continuation) { new Thread(() => { Thread.Sleep(3000); continuation(); } ).Start(); } public bool IsCompleted { get { return false; } } public void GetResult() { } } } }
C#会把MessageBox.Show封装成continuation()传给OnComplete()函数。