创建自己的awaitable类型

From: http://www.cnblogs.com/TianFang/archive/2012/09/21/2696769.html

在C# 5.0中引入了await关键字,通过它可以非常容易的实现异步操作。在大多数的时候,await一般适合Task一起使用的,也非常方便。但有的时候,我们也需要自定义我们自己的awaitable类型,以实现更高的灵活性和效率。

可以用于await运算符的对象要求如下:

  1. 有一个GetAwaiter()方法或扩展方法,它返回一个实现了INotifyCompletion接口的awaiter对象(或结构)
  2. 返回的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式的异步操作了:

  1. 编译器把后续操作封装为一个Action对象continuation传入awaiter的OnCompleted函数并执行。
  2. awaiter在OnCompleted函数中执行异步操作,并在异步操作完成后(一般是异步调用的回调函数)执行continuation操作。
  3. 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()函数。

原文地址:https://www.cnblogs.com/puncha/p/3877019.html