private static void ContinueOnSameSynchronizationContext(AwaitAdapter awaiter, Action continuation)
        {
            if (awaiter == null)
            {
                throw new ArgumentNullException(nameof(awaiter));
            }
            if (continuation == null)
            {
                throw new ArgumentNullException(nameof(continuation));
            }

            var context = SynchronizationContext.Current;

            awaiter.OnCompleted(() =>
            {
                if (SynchronizationContext.Current == context)
                {
                    continuation.Invoke();
                }
                else
                {
                    context.Post(state => ((Action)state).Invoke(), state: continuation);
                }
            });
        }
            public override void WaitForCompletion(AwaitAdapter awaiter)
            {
                var context = SynchronizationContext.Current;

                if (!IsApplicable(context))
                {
                    throw new InvalidOperationException("This strategy must only be used from a WindowsFormsSynchronizationContext.");
                }

                if (awaiter.IsCompleted)
                {
                    return;
                }

                // Wait for a post rather than scheduling the continuation now. If there has been a race condition
                // and it completed after the IsCompleted check, it will wait until the application runs *before*
                // shutting it down. Otherwise Application.Exit is a no-op and we would then proceed to do
                // Application.Run and never return.
                context.Post(
                    state => ContinueOnSameSynchronizationContext((AwaitAdapter)state, _applicationExit),
                    state: awaiter);

                try
                {
                    _applicationRun.Invoke();
                }
                finally
                {
                    SynchronizationContext.SetSynchronizationContext(context);
                }
            }
示例#3
0
            public override object WaitForPendingOperationsToComplete(object invocationResult)
            {
                var awaitAdapter = AwaitAdapter.FromAwaitable(invocationResult);

                if (!awaitAdapter.IsCompleted)
                {
                    var waitStrategy = MessagePumpStrategy.FromCurrentSynchronizationContext();
                    waitStrategy.WaitForCompletion(awaitAdapter);
                }

                // Future: instead of Wait(), use GetAwaiter() to check awaiter.IsCompleted above
                // and use awaiter.OnCompleted/awaiter.GetResult below.
                // (Implement a ReflectionAwaitAdapter)
                try
                {
                    invocationResult.GetType().GetMethod(TaskWaitMethod, new Type[0]).Invoke(invocationResult, null);
                }
                catch (TargetInvocationException e)
                {
                    IList <Exception> innerExceptions = GetAllExceptions(e.InnerException);
                    ExceptionHelper.Rethrow(innerExceptions[0]);
                }
                var args = invocationResult.GetType().GetGenericArguments();

                if (args != null && args.Length == 1 && args[0].Name == VoidTaskResultType)
                {
                    return(null);
                }

                PropertyInfo taskResultProperty = invocationResult.GetType().GetProperty(TaskResultProperty, TaskResultPropertyBindingFlags);

                return(taskResultProperty != null?taskResultProperty.GetValue(invocationResult, null) : invocationResult);
            }
示例#4
0
        public static AwaitAdapter TryCreate(object awaitable)
        {
            if (awaitable == null)
            {
                return(null);
            }

            var info = GetAsyncInfo(awaitable.GetType());

            if (info == null)
            {
                return(null);
            }

            if (_startImmediateAsTaskMethod == null)
            {
                var asyncHelperMethodsType = info.FSharpAsyncTypeDefinition.GetTypeInfo().Assembly.GetType("Microsoft.FSharp.Control.FSharpAsync");
                if (asyncHelperMethodsType == null)
                {
                    throw new InvalidOperationException("Cannot find non-generic FSharpAsync type in the same assembly as the generic one.");
                }

                _startImmediateAsTaskMethod = asyncHelperMethodsType
                                              .GetMethods(BindingFlags.Public | BindingFlags.Static)
                                              .Single(method =>
                {
                    if (method.Name != "StartImmediateAsTask")
                    {
                        return(false);
                    }
                    var typeArguments = method.GetGenericArguments();
                    if (typeArguments.Length != 1)
                    {
                        return(false);
                    }

                    var parameters = method.GetParameters();
                    if (parameters.Length != 2)
                    {
                        return(false);
                    }

                    if (parameters[0].ParameterType != info.FSharpAsyncTypeDefinition.MakeGenericType(typeArguments[0]))
                    {
                        return(false);
                    }

                    Type someType;
                    return(parameters[1].ParameterType.IsFSharpOption(out someType) &&
                           someType.FullName == "System.Threading.CancellationToken");
                });
            }

            var task = _startImmediateAsTaskMethod
                       .MakeGenericMethod(info.ResultType)
                       .Invoke(null, new[] { awaitable, null });

            return(AwaitAdapter.FromAwaitable(task));
        }
示例#5
0
        public static object Await(Func <object> invoke)
        {
            Guard.ArgumentNotNull(invoke, nameof(invoke));

            using (InitializeExecutionEnvironment())
            {
                var awaitAdapter = AwaitAdapter.FromAwaitable(invoke.Invoke());

                if (!awaitAdapter.IsCompleted)
                {
                    var waitStrategy = MessagePumpStrategy.FromCurrentSynchronizationContext();
                    waitStrategy.WaitForCompletion(awaitAdapter);
                }

                return(awaitAdapter.GetResult());
            }
        }
示例#6
0
        public static object Await(Func <object> invoke)
        {
            Guard.ArgumentNotNull(invoke, nameof(invoke));

            object invocationResult;

            using (InitializeExecutionEnvironment())
            {
                invocationResult = invoke.Invoke();
                if (invocationResult == null || !IsTaskType(invocationResult.GetType()))
                {
                    throw new InvalidOperationException("The delegate did not return a Task."); // General awaitable support coming soon.
                }
                var awaitAdapter = AwaitAdapter.FromAwaitable(invocationResult);

                if (!awaitAdapter.IsCompleted)
                {
                    var waitStrategy = MessagePumpStrategy.FromCurrentSynchronizationContext();
                    waitStrategy.WaitForCompletion(awaitAdapter);
                }
            }

            // Future: instead of Wait(), use GetAwaiter() to check awaiter.IsCompleted above
            // and use awaiter.OnCompleted/awaiter.GetResult below.
            // (Implement a ReflectionAwaitAdapter)
            try
            {
                invocationResult.GetType().GetMethod(TaskWaitMethod, new Type[0]).Invoke(invocationResult, null);
            }
            catch (TargetInvocationException e)
            {
                IList <Exception> innerExceptions = GetAllExceptions(e.InnerException);
                ExceptionHelper.Rethrow(innerExceptions[0]);
            }
            var genericArguments = invocationResult.GetType().GetGenericArguments();

            if (genericArguments.Length == 1 && genericArguments[0].Name == VoidTaskResultType)
            {
                return(null);
            }

            PropertyInfo taskResultProperty = invocationResult.GetType().GetProperty(TaskResultProperty, TaskResultPropertyBindingFlags);

            return(taskResultProperty != null?taskResultProperty.GetValue(invocationResult, null) : invocationResult);
        }
            public override void WaitForCompletion(AwaitAdapter awaiter)
            {
                var context = SynchronizationContext.Current as SingleThreadedTestSynchronizationContext;

                if (context == null)
                {
                    throw new InvalidOperationException("This strategy must only be used from a SingleThreadedTestSynchronizationContext.");
                }

                if (awaiter.IsCompleted)
                {
                    return;
                }

                // Wait for a post rather than scheduling the continuation now. If there has been a race condition
                // and it completed after the IsCompleted check, it will wait until the message loop runs *before*
                // shutting it down. Otherwise context.ShutDown will throw.
                context.Post(
                    state => ContinueOnSameSynchronizationContext((AwaitAdapter)state, context.ShutDown),
                    state: awaiter);

                context.Run();
            }
示例#8
0
 /// <summary>
 /// Check that setup and teardown methods marked by certain attributes
 /// meet NUnit's requirements and mark the tests not runnable otherwise.
 /// </summary>
 protected void CheckSetUpTearDownMethods(MethodInfo[] methods)
 {
     foreach (MethodInfo method in methods)
     {
         if (method.IsAbstract)
         {
             MakeInvalid("An abstract SetUp and TearDown methods cannot be run: " + method.Name);
         }
         else if (!(method.IsPublic || method.IsFamily))
         {
             MakeInvalid("SetUp and TearDown methods must be public or protected: " + method.Name);
         }
         else if (method.GetParameters().Length != 0)
         {
             MakeInvalid("SetUp and TearDown methods must not have parameters: " + method.Name);
         }
         else if (AsyncToSyncAdapter.IsAsyncOperation(method))
         {
             if (method.ReturnType == typeof(void))
             {
                 MakeInvalid("SetUp and TearDown methods must not be async void: " + method.Name);
             }
             else if (!Reflect.IsVoidOrUnit(AwaitAdapter.GetResultType(method.ReturnType)))
             {
                 MakeInvalid("SetUp and TearDown methods must return void or an awaitable type with a void result: " + method.Name);
             }
         }
         else
         {
             if (!Reflect.IsVoidOrUnit(method.ReturnType))
             {
                 MakeInvalid("SetUp and TearDown methods must return void or an awaitable type with a void result: " + method.Name);
             }
         }
     }
 }
            public override void WaitForCompletion(AwaitAdapter awaitable)
            {
                var context = SynchronizationContext.Current;

                if (!(context is DispatcherSynchronizationContext))
                {
                    throw new InvalidOperationException("This strategy must only be used from a DispatcherSynchronizationContext.");
                }

                if (awaitable.IsCompleted)
                {
                    return;
                }

                // Wait for a post rather than scheduling the continuation now. If there has been a race condition
                // and it completed after the IsCompleted check, it will wait until the application runs *before*
                // shutting it down. Otherwise Dispatcher.ExitAllFrames is a no-op and we would then proceed to do
                // Dispatcher.Run and never return.
                context.Post(
                    state => ContinueOnSameSynchronizationContext((AwaitAdapter)state, Dispatcher.ExitAllFrames),
                    state: awaitable);

                Dispatcher.Run();
            }
 public override void WaitForCompletion(AwaitAdapter awaiter)
 {
     awaiter.BlockUntilCompleted();
 }
 public abstract void WaitForCompletion(AwaitAdapter awaiter);
示例#12
0
 public static bool IsAsyncOperation(MethodInfo method)
 {
     return(AwaitAdapter.IsAwaitable(method.ReturnType) ||
            method.GetCustomAttributes(false).Any(attr => attr.GetType().FullName == "System.Runtime.CompilerServices.AsyncStateMachineAttribute"));
 }
示例#13
0
 public override Task WaitForCompletion(AwaitAdapter awaiter)
 {
     return(awaiter.BlockUntilCompleted());
 }
示例#14
0
 public abstract Task WaitForCompletion(AwaitAdapter awaiter);