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

MessagePumpStrategy

abstract class MessagePumpStrategy
using System; using System.Diagnostics.CodeAnalysis; using System.Reflection; using System.Runtime.CompilerServices; using System.Threading; namespace NUnit.Framework.Internal { [System.Runtime.CompilerServices.NullableContext(1)] [System.Runtime.CompilerServices.Nullable(0)] internal abstract class MessagePumpStrategy { [System.Runtime.CompilerServices.Nullable(0)] private sealed class NoMessagePumpStrategy : MessagePumpStrategy { public static readonly NoMessagePumpStrategy Instance = new NoMessagePumpStrategy(); private NoMessagePumpStrategy() { } public override void WaitForCompletion(AwaitAdapter awaiter) { awaiter.BlockUntilCompleted(); } } [System.Runtime.CompilerServices.Nullable(0)] private sealed class WindowsFormsMessagePumpStrategy : MessagePumpStrategy { [System.Runtime.CompilerServices.Nullable(2)] private static WindowsFormsMessagePumpStrategy _instance; private readonly Action _applicationRun; private readonly Action _applicationExit; private WindowsFormsMessagePumpStrategy(Action applicationRun, Action applicationExit) { _applicationRun = applicationRun; _applicationExit = applicationExit; } [System.Runtime.CompilerServices.NullableContext(2)] public static MessagePumpStrategy GetIfApplicable() { if (!IsApplicable(SynchronizationContext.Current)) return null; if (_instance == null) { Type type = SynchronizationContext.Current.GetType().Assembly.GetType("System.Windows.Forms.Application", true); Action applicationRun = (Action)type.GetMethod("Run", BindingFlags.DeclaredOnly | BindingFlags.Static | BindingFlags.Public, null, Type.EmptyTypes, null).CreateDelegate(typeof(Action)); Action applicationExit = (Action)type.GetMethod("Exit", BindingFlags.DeclaredOnly | BindingFlags.Static | BindingFlags.Public, null, Type.EmptyTypes, null).CreateDelegate(typeof(Action)); _instance = new WindowsFormsMessagePumpStrategy(applicationRun, applicationExit); } return _instance; } [System.Runtime.CompilerServices.NullableContext(2)] private static bool IsApplicable([NotNullWhen(true)] SynchronizationContext context) { return context?.GetType().FullName == "System.Windows.Forms.WindowsFormsSynchronizationContext"; } public override void WaitForCompletion(AwaitAdapter awaiter) { SynchronizationContext current = SynchronizationContext.Current; if (!IsApplicable(current)) throw new InvalidOperationException("This strategy must only be used from a WindowsFormsSynchronizationContext."); if (!awaiter.IsCompleted) { current.Post(delegate { ContinueOnSameSynchronizationContext(awaiter, _applicationExit); }, awaiter); try { _applicationRun(); } finally { SynchronizationContext.SetSynchronizationContext(current); } } } } [System.Runtime.CompilerServices.Nullable(0)] private sealed class WpfMessagePumpStrategy : MessagePumpStrategy { [System.Runtime.CompilerServices.Nullable(2)] private static WpfMessagePumpStrategy _instance; private readonly MethodInfo _dispatcherPushFrame; private readonly MethodInfo _dispatcherFrameSetContinueProperty; private readonly Type _dispatcherFrameType; private WpfMessagePumpStrategy(MethodInfo dispatcherPushFrame, MethodInfo dispatcherFrameSetContinueProperty, Type dispatcherFrameType) { _dispatcherPushFrame = dispatcherPushFrame; _dispatcherFrameSetContinueProperty = dispatcherFrameSetContinueProperty; _dispatcherFrameType = dispatcherFrameType; } [System.Runtime.CompilerServices.NullableContext(2)] public static MessagePumpStrategy GetIfApplicable() { SynchronizationContext current = SynchronizationContext.Current; if (!IsApplicable(current)) return null; if (_instance == null) { Assembly assembly = current.GetType().Assembly; Type type = assembly.GetType("System.Windows.Threading.Dispatcher", true); Type type2 = assembly.GetType("System.Windows.Threading.DispatcherFrame", true); MethodInfo method = type.GetMethod("PushFrame", BindingFlags.DeclaredOnly | BindingFlags.Static | BindingFlags.Public, null, new Type[1] { type2 }, null); MethodInfo dispatcherFrameSetContinueProperty = type2.GetProperty("Continue")?.GetSetMethod(); _instance = new WpfMessagePumpStrategy(method, dispatcherFrameSetContinueProperty, type2); } return _instance; } [System.Runtime.CompilerServices.NullableContext(2)] private static bool IsApplicable([NotNullWhen(true)] SynchronizationContext context) { return context?.GetType().FullName == "System.Windows.Threading.DispatcherSynchronizationContext"; } public override void WaitForCompletion(AwaitAdapter awaiter) { SynchronizationContext current = SynchronizationContext.Current; if (!IsApplicable(current)) throw new InvalidOperationException("This strategy must only be used from a DispatcherSynchronizationContext."); if (!awaiter.IsCompleted) { object frame = Activator.CreateInstance(_dispatcherFrameType, true); current.Post(delegate { ContinueOnSameSynchronizationContext(awaiter, delegate { _dispatcherFrameSetContinueProperty.Invoke(frame, new object[1] { false }); }); }, awaiter); _dispatcherPushFrame.Invoke(null, new object[1] { frame }); } } } [System.Runtime.CompilerServices.Nullable(0)] private sealed class SingleThreadedTestMessagePumpStrategy : MessagePumpStrategy { public static readonly SingleThreadedTestMessagePumpStrategy Instance = new SingleThreadedTestMessagePumpStrategy(); private SingleThreadedTestMessagePumpStrategy() { } public override void WaitForCompletion(AwaitAdapter awaiter) { SingleThreadedTestSynchronizationContext obj = SynchronizationContext.Current as SingleThreadedTestSynchronizationContext; if (obj == null) throw new InvalidOperationException("This strategy must only be used from a SingleThreadedTestSynchronizationContext."); SingleThreadedTestSynchronizationContext context = obj; if (!awaiter.IsCompleted) { context.Post(delegate { ContinueOnSameSynchronizationContext(awaiter, context.ShutDown); }, awaiter); context.Run(); } } } public abstract void WaitForCompletion(AwaitAdapter awaiter); public static MessagePumpStrategy FromCurrentSynchronizationContext() { SynchronizationContext current = SynchronizationContext.Current; if (current is SingleThreadedTestSynchronizationContext) return SingleThreadedTestMessagePumpStrategy.Instance; return WindowsFormsMessagePumpStrategy.GetIfApplicable() ?? WpfMessagePumpStrategy.GetIfApplicable() ?? NoMessagePumpStrategy.Instance; } private static void ContinueOnSameSynchronizationContext(AwaitAdapter awaiter, Action continuation) { if (awaiter == null) throw new ArgumentNullException("awaiter"); if (continuation == null) throw new ArgumentNullException("continuation"); SynchronizationContext context = SynchronizationContext.Current; awaiter.OnCompleted(delegate { if (context == null || SynchronizationContext.Current == context) continuation(); else context.Post(delegate { continuation(); }, continuation); }); } } }