public static Task Run(Func <Task> asyncMethod) { using (SynchronizationContextSwitcher.Capture()) { var customContext = new Context(); SynchronizationContext.SetSynchronizationContext(customContext); var task = asyncMethod.Invoke(); if (task != null) { // register a continuation with the task, which will shut down the loop when the task completes. task.ContinueWith(_ => customContext.WorkQueue.Shutdown(), TaskContinuationOptions.ExecuteSynchronously); } else { // the delegate returned a null Task (VB/C# compilers never do this for async methods) // we don't have anything to register continuations with in this case, so just return immediately return(task); } customContext.WorkQueue.ExecuteWorkQueueLoop(); task.RethrowForCompletedTasks(); return(task); } }
/// <summary> /// Runs the action inside a message loop and continues looping work items /// as long as any asynchronous operations have been registered /// </summary> public static void Run(Action asyncAction) { using (SynchronizationContextSwitcher.Capture()) { var customContext = new VoidContext(); SynchronizationContext.SetSynchronizationContext(customContext); // Do an explicit increment/decrement. // Our sync context does a check on decrement, to see if there are any // outstanding asynchronous operations (async void methods register this correctly). // If there aren't any registerd operations, then it will exit the loop customContext.OperationStarted(); try { asyncAction.Invoke(); } finally { customContext.OperationCompleted(); } customContext.WorkQueue.ExecuteWorkQueueLoop(); // ExecuteWorkQueueLoop() has returned. This must indicate that // the operation count has fallen back to zero. } }