<PackageReference Include="NUnit" Version="4.2.2" />

CSharpPatternBasedAwaitAdapter

using System; using System.Collections.Concurrent; using System.Reflection; using System.Runtime.CompilerServices; namespace NUnit.Framework.Internal { [System.Runtime.CompilerServices.NullableContext(1)] [System.Runtime.CompilerServices.Nullable(0)] internal static class CSharpPatternBasedAwaitAdapter { [System.Runtime.CompilerServices.Nullable(0)] private sealed class AwaitShapeInfo { private readonly MethodInfo _getAwaiterMethod; private readonly MethodInfo _isCompletedGetter; private readonly MethodInfo _onCompletedMethod; private readonly MethodInfo _getResultMethod; public Type ResultType => _getResultMethod.ReturnType; public AwaitShapeInfo(MethodInfo getAwaiterMethod, MethodInfo isCompletedGetter, MethodInfo onCompletedMethod, MethodInfo getResultMethod) { _getAwaiterMethod = getAwaiterMethod; _isCompletedGetter = isCompletedGetter; _onCompletedMethod = onCompletedMethod; _getResultMethod = getResultMethod; } [return: System.Runtime.CompilerServices.Nullable(2)] public static AwaitShapeInfo TryCreate(Type awaitableType) { MethodInfo nonGenericPublicInstanceMethod = awaitableType.GetNonGenericPublicInstanceMethod("GetAwaiter", Type.EmptyTypes); if ((object)nonGenericPublicInstanceMethod == null || nonGenericPublicInstanceMethod.GetGenericArguments().Length != 0) return null; Type returnType = nonGenericPublicInstanceMethod.ReturnType; Type interface = returnType.GetInterface("System.Runtime.CompilerServices.INotifyCompletion"); if ((object)interface == null) return null; MethodInfo nonGenericPublicInstanceMethod2 = interface.GetNonGenericPublicInstanceMethod("OnCompleted", new Type[1] { typeof(Action) }); if ((object)nonGenericPublicInstanceMethod2 == null) return null; PropertyInfo publicInstanceProperty = returnType.GetPublicInstanceProperty("IsCompleted", Type.EmptyTypes); if ((object)publicInstanceProperty == null || publicInstanceProperty.PropertyType != typeof(bool)) return null; MethodInfo getMethod = publicInstanceProperty.GetGetMethod(); if ((object)getMethod == null) return null; MethodInfo nonGenericPublicInstanceMethod3 = returnType.GetNonGenericPublicInstanceMethod("GetResult", Type.EmptyTypes); if ((object)nonGenericPublicInstanceMethod3 == null) return null; MethodInfo methodInfo = returnType.GetInterface("System.Runtime.CompilerServices.ICriticalNotifyCompletion")?.GetNonGenericPublicInstanceMethod("UnsafeOnCompleted", new Type[1] { typeof(Action) }); return new AwaitShapeInfo(nonGenericPublicInstanceMethod, getMethod, methodInfo ?? nonGenericPublicInstanceMethod2, nonGenericPublicInstanceMethod3); } public AwaitAdapter CreateAwaitAdapter(object awaitable) { return new ReflectionAdapter(_getAwaiterMethod.InvokeWithTransparentExceptions(awaitable), _isCompletedGetter, _onCompletedMethod, _getResultMethod); } } [System.Runtime.CompilerServices.Nullable(0)] private sealed class ReflectionAdapter : DefaultBlockingAwaitAdapter { [System.Runtime.CompilerServices.Nullable(2)] private readonly object _awaiter; private readonly Func<bool> _awaiterIsCompleted; private readonly Action<Action> _awaiterOnCompleted; private readonly MethodInfo _getResultMethod; public override bool IsCompleted => _awaiterIsCompleted(); public ReflectionAdapter([System.Runtime.CompilerServices.Nullable(2)] object awaiter, MethodInfo isCompletedGetter, MethodInfo onCompletedMethod, MethodInfo getResultMethod) { _awaiter = awaiter; _awaiterIsCompleted = (Func<bool>)isCompletedGetter.CreateDelegate(typeof(Func<bool>), awaiter); _awaiterOnCompleted = (Action<Action>)onCompletedMethod.CreateDelegate(typeof(Action<Action>), awaiter); _getResultMethod = getResultMethod; } public override void OnCompleted(Action action) { _awaiterOnCompleted(action); } [System.Runtime.CompilerServices.NullableContext(2)] public override object GetResult() { return _getResultMethod.InvokeWithTransparentExceptions(_awaiter); } } [System.Runtime.CompilerServices.Nullable(new byte[] { 1, 1, 2 })] private static readonly ConcurrentDictionary<Type, AwaitShapeInfo> ShapeInfoByType = new ConcurrentDictionary<Type, AwaitShapeInfo>(); [System.Runtime.CompilerServices.NullableContext(2)] public static AwaitAdapter TryCreate(object awaitable) { if (awaitable == null) return null; return GetShapeInfo(awaitable.GetType())?.CreateAwaitAdapter(awaitable); } public static bool IsAwaitable(Type awaitableType) { return GetShapeInfo(awaitableType) != null; } [return: System.Runtime.CompilerServices.Nullable(2)] public static Type GetResultType(Type awaitableType) { return GetShapeInfo(awaitableType)?.ResultType; } [return: System.Runtime.CompilerServices.Nullable(2)] private static AwaitShapeInfo GetShapeInfo(Type type) { return ShapeInfoByType.GetOrAdd(type, AwaitShapeInfo.TryCreate); } } }