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

FSharpAsyncAwaitAdapter

using System; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; namespace NUnit.Framework.Internal { [NullableContext(1)] [Nullable(0)] internal static class FSharpAsyncAwaitAdapter { [Nullable(0)] private sealed class AsyncInfo { public Type FSharpAsyncTypeDefinition { get; } public Type ResultType { get; } public AsyncInfo(Type fSharpAsyncTypeDefinition, Type resultType) { FSharpAsyncTypeDefinition = fSharpAsyncTypeDefinition; ResultType = resultType; } } [Nullable(2)] private static MethodInfo _startImmediateAsTaskMethod; public static bool IsAwaitable(Type awaitableType) { return GetAsyncInfo(awaitableType) != null; } [return: Nullable(2)] public static Type GetResultType(Type awaitableType) { return GetAsyncInfo(awaitableType)?.ResultType; } [return: Nullable(2)] private static AsyncInfo GetAsyncInfo(Type asyncType) { if ((object)asyncType == null) return null; if (!asyncType.IsGenericType) return null; Type genericTypeDefinition = asyncType.GetGenericTypeDefinition(); if (genericTypeDefinition.FullName != "Microsoft.FSharp.Control.FSharpAsync`1") return null; return new AsyncInfo(genericTypeDefinition, asyncType.GetGenericArguments()[0]); } [return: Nullable(2)] public static AwaitAdapter TryCreate(object awaitable) { if (awaitable == null) return null; AsyncInfo info = GetAsyncInfo(awaitable.GetType()); if (info == null) return null; if ((object)_startImmediateAsTaskMethod == null) { Type type = info.FSharpAsyncTypeDefinition.Assembly.GetType("Microsoft.FSharp.Control.FSharpAsync"); if ((object)type == null) throw new InvalidOperationException("Cannot find non-generic FSharpAsync type in the same assembly as the generic one."); _startImmediateAsTaskMethod = type.GetMethods(BindingFlags.Static | BindingFlags.Public).Single(delegate(MethodInfo method) { if (method.Name != "StartImmediateAsTask") return false; Type[] genericArguments = method.GetGenericArguments(); if (genericArguments.Length != 1) return false; ParameterInfo[] parameters = method.GetParameters(); if (parameters.Length != 2) return false; if (parameters[0].ParameterType != info.FSharpAsyncTypeDefinition.MakeGenericType(genericArguments[0])) return false; if (parameters[1].ParameterType.IsFSharpOption(out Type someType)) return someType.FullName == "System.Threading.CancellationToken"; return false; }); } object awaitable2 = _startImmediateAsTaskMethod.MakeGenericMethod(info.ResultType).Invoke(null, new object[2] { awaitable, null }); return AwaitAdapter.FromAwaitable(awaitable2); } } }