实现一个可以用 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(); } } }