实现一个可以用 await 异步等待的 Awaiter

总结起来,要想使一个方法可被 await 等待,必须具备以下条件:

这个方法返回一个类 A 的实例,这个类 A 必须满足后面的条件。
此类 A 有一个可被访问到的 GetAwaiter 方法(扩展方法也行,这算是黑科技吗?),方法返回类 B 的实例,这个类 B 必须满足后面的条件;
此类 B 实现 INotifyCompletion 接口,且拥有 bool IsCompleted { get; } 属性、GetResult() 方法、void OnCompleted(Action continuation) 方法。
https://blog.csdn.net/WPwalter/article/details/78387736

using System.Runtime.CompilerServices;

namespace Walterlv.Threading
{
    /// <summary>
    /// 表示一个可等待对象,如果一个方法返回此类型的实例,则此方法可以使用 `await` 异步等待。
    /// </summary>
    /// <typeparam name="TAwaiter">用于给 await 确定返回时机的 IAwaiter 的实例。</typeparam>
    public interface IAwaitable<out TAwaiter> where TAwaiter : IAwaiter
    {
        /// <summary>
        /// 获取一个可用于 await 关键字异步等待的异步等待对象。
        /// 此方法会被编译器自动调用。
        /// </summary>
        TAwaiter GetAwaiter();
    }

    /// <summary>
    /// 表示一个包含返回值的可等待对象,如果一个方法返回此类型的实例,则此方法可以使用 `await` 异步等待返回值。
    /// </summary>
    /// <typeparam name="TAwaiter">用于给 await 确定返回时机的 IAwaiter{<typeparamref name="TResult"/>} 的实例。</typeparam>
    /// <typeparam name="TResult">异步返回的返回值类型。</typeparam>
    public interface IAwaitable<out TAwaiter, out TResult> where TAwaiter : IAwaiter<TResult>
    {
        /// <summary>
        /// 获取一个可用于 await 关键字异步等待的异步等待对象。
        /// 此方法会被编译器自动调用。
        /// </summary>
        TAwaiter GetAwaiter();
    }

    /// <summary>
    /// 用于给 await 确定异步返回的时机。
    /// </summary>
    public interface IAwaiter : INotifyCompletion
    {
        /// <summary>
        /// 获取一个状态,该状态表示正在异步等待的操作已经完成(成功完成或发生了异常);此状态会被编译器自动调用。
        /// 在实现中,为了达到各种效果,可以灵活应用其值:可以始终为 true,或者始终为 false。
        /// </summary>
        bool IsCompleted { get; }

        /// <summary>
        /// 此方法会被编译器在 await 结束时自动调用以获取返回状态(包括异常)。
        /// </summary>
        void GetResult();
    }

    /// <summary>
    /// 当执行关键代码(此代码中的错误可能给应用程序中的其他状态造成负面影响)时,
    /// 用于给 await 确定异步返回的时机。
    /// </summary>
    public interface ICriticalAwaiter : IAwaiter, ICriticalNotifyCompletion
    {
    }

    /// <summary>
    /// 用于给 await 确定异步返回的时机,并获取到返回值。
    /// </summary>
    /// <typeparam name="TResult">异步返回的返回值类型。</typeparam>
    public interface IAwaiter<out TResult> : INotifyCompletion
    {
        /// <summary>
        /// 获取一个状态,该状态表示正在异步等待的操作已经完成(成功完成或发生了异常);此状态会被编译器自动调用。
        /// 在实现中,为了达到各种效果,可以灵活应用其值:可以始终为 true,或者始终为 false。
        /// </summary>
        bool IsCompleted { get; }

        /// <summary>
        /// 获取此异步等待操作的返回值,此方法会被编译器在 await 结束时自动调用以获取返回值(包括异常)。
        /// </summary>
        /// <returns>异步操作的返回值。</returns>
        TResult GetResult();
    }

    /// <summary>
    /// 当执行关键代码(此代码中的错误可能给应用程序中的其他状态造成负面影响)时,
    /// 用于给 await 确定异步返回的时机,并获取到返回值。
    /// </summary>
    /// <typeparam name="TResult">异步返回的返回值类型。</typeparam>
    public interface ICriticalAwaiter<out TResult> : IAwaiter<TResult>, ICriticalNotifyCompletion
    {
    }
}

  

 https://stackoverflow.com/questions/19535147/await-and-synchronizationcontext-in-a-managed-component-hosted-by-an-unmanaged-a/19555959#19555959

public class ContextAwaiter<T> : INotifyCompletion
    {
        readonly Control _control;
        readonly TaskAwaiter<T> _awaiter;
        readonly bool _alwaysAsync;

        public ContextAwaiter(Task<T> task, Control control, bool alwaysAsync)
        {
            _awaiter = task.GetAwaiter();
            _control = control;
            _alwaysAsync = alwaysAsync;
        }

        public ContextAwaiter<T> GetAwaiter() { return this; }

        public bool IsCompleted { get { return !_alwaysAsync && _awaiter.IsCompleted; } }

        public void OnCompleted(Action continuation)
        {
            if (_alwaysAsync || _control.InvokeRequired)
            {
                Action<Action> callback = (c) => _awaiter.OnCompleted(c);
                _control.BeginInvoke(callback, continuation);
            }
            else
                _awaiter.OnCompleted(continuation);
        }

        public T GetResult()
        {
            return _awaiter.GetResult();
        }
    }
}

  

posted @ 2019-05-23 11:06  Charltsing  阅读(1116)  评论(0编辑  收藏  举报