C#里面的async/await语法简直好用的不要不要的。但是,如果我想让这种异步状态机,能工作在我自定义的线程里面要怎么办呢?

要让编译器识别async await 语法首先需要具备以下条件:
1、 可等待的对象,需要实现T GetAwaiter();方法。注意:T可以是任何类型,不一定是object类型。

可等待对象无返回值需要满足的条件: 1)、继承接口INotifyCompletion或实现void OnCompleted(Action continuation);方法。
2)、实现bool IsCompleted { get; }属性。 3)、实现void GetResult();方法。

可等待对象带返回值需要满足的条件: 1)、继承接口INotifyCompletion或实现void OnCompleted(Action continuation);方法。
2)、实现bool IsCompleted { get; }属性。 3)、实现T GetResult();方法。T可以是任意类型。

具备上述条件,你的代码就可以顺利编译通过了。但是此时的代码,还不能工作,因为你还没有给状态机增加状态!

为了增加这个状态,我们增加一个方法void ReportCompleted(T result);,用来更改状态机的状态值,表示我们要执行的异步操作是否已完成。

具体代码,如下所示:

相关的接口定义:


    /// <summary>
    /// 带返回值的可等待对象
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public interface IAwaitable<T> : INotifyCompletion
    {
        bool IsCompleted { get; }
        T Result { get; }
        T GetResult();
        void ReportCompleted(T result);
    }

    /// <summary>
    /// 不带返回值的可等待对象
    /// </summary>
    public interface IAwaitable : INotifyCompletion
    {
        bool IsCompleted { get; }
        void GetResult();
        void ReportCompleted();
    }

    /// <summary>
    /// 获取可等待者
    /// </summary>
    public interface IAwaiter
    {
        IAwaitable GetAwaiter();
    }

    /// <summary>
    /// 获取可等待者
    /// </summary>
    public interface IAwaiter<T>
    {
        IAwaitable<T> GetAwaiter();
    }


    /// <summary>
    /// 不带返回值的可等待的任务
    /// </summary>
    public class AwaitableTask : IAwaiter
    {
        public AwaitableTask()
        {
            AwaitableObject = new AwaitableObject();
        }

        /// <summary>
        /// 获取可等待的对象
        /// </summary>
        public IAwaitable GetAwaiter()
        {
            return AwaitableObject;
        }

        /// <summary>
        /// 实现相关接口的可等待的对象
        /// </summary>
        public AwaitableObject AwaitableObject { get; private set; }
    }

    /// <summary>
    /// 带返回值的可等待的任务
    /// </summary>
    public class AwaitableTask<T> : IAwaiter<T>
    {
        public AwaitableTask()
        {
            AwaitableObject = new AwaitableObject<T>();
        }

        public IAwaitable<T> GetAwaiter()
        {
            return AwaitableObject;
        }

        public AwaitableObject<T> AwaitableObject { get; private set; }
    }

    /// <summary>
    /// 不带返回值的可等待的状态对象
    /// </summary>
    public class AwaitableObject : Awaitable, IAwaitable
    {
        public void GetResult()
        {

        }
    }

    /// <summary>
    /// 带返回值的可等待的状态对象
    /// </summary>
    public class AwaitableObject<T> : Awaitable, IAwaitable<T>
    {
        public T Result { get; private set; }

        public T GetResult()
        {
            return Result;
        }

        public void ReportCompleted(T result)
        {
            Result = result;
            ReportCompleted();
        }
    }

    /// <summary>
    /// 可等待的抽象类,状态机的具体实现
    /// </summary>
    public abstract class Awaitable
    {
        private Action _continuation;

        private readonly object _locker = new object();

        public bool IsCompleted { get; private set; }

        public void OnCompleted(Action continuation)
        {
            //因为此处调用和ReportCompleted,可能不在一个线程上,会出现时机问题
            lock (_locker)
            {
                if (IsCompleted)
                {
                    continuation?.Invoke();
                }
                else
                {
                    _continuation += continuation;
                }
            }
        }

        //用于通知,当前任务已经完成。
        public void ReportCompleted()
        {
            lock (_locker)
            {
                IsCompleted = true;
                var continuation = _continuation;
                _continuation = null;
                continuation?.Invoke();
            }
        }

        //重置状态,让状态机恢复可等待
        public void Reset()
        {
            lock (_locker)
            {
                _continuation?.Invoke();
                IsCompleted = false;
                _continuation = null;
            }
        }
    }

欢迎转载分享,请关注微信公众号,将同步更新博客,方便查看!

承哥技术交流小作坊


本文会经常更新,请阅读原文: https://huchengv5.gitee.io//post/C-%E8%AE%A4%E8%AF%86asyncawait-%E5%A6%82%E4%BD%95%E8%87%AA%E5%B7%B1%E5%8A%A8%E6%89%8B%E7%BC%96%E5%86%99%E5%8F%AF%E7%AD%89%E5%BE%85%E7%9A%84%E4%BB%BB%E5%8A%A1.html ,以避免陈旧错误知识的误导,同时有更好的阅读体验。

知识共享许可协议 本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。欢迎转载、使用、重新发布,但务必保留文章署名胡承(包含链接: https://huchengv5.gitee.io/ ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请 与我联系