#if NET20 || NET30 || NET35 || !NET_4_6 using System.Diagnostics.Contracts; using System.Security; namespace System.Threading.Tasks { /// Task continuation for awaiting with a current synchronization context. internal sealed class SynchronizationContextAwaitTaskContinuation : AwaitTaskContinuation { /// SendOrPostCallback delegate to invoke the action. private static readonly SendOrPostCallback _postCallback = state => ((Action)state)(); // can't use InvokeAction as it's SecurityCritical /// Cached delegate for PostAction [SecurityCritical] private static ContextCallback _postActionCallback; /// The context with which to run the action. private readonly SynchronizationContext _syncContext; /// Initializes the SynchronizationContextAwaitTaskContinuation. /// The synchronization context with which to invoke the action. Must not be null. /// The action to invoke. Must not be null. /// Whether to capture and restore ExecutionContext. [SecurityCritical] internal SynchronizationContextAwaitTaskContinuation(SynchronizationContext context, Action action, bool flowExecutionContext) : base(action, flowExecutionContext) { Contract.Assert(context != null); _syncContext = context; } [SecuritySafeCritical] internal override void Run(Task completedTask, bool canInlineContinuationTask) { // If we're allowed to inline, run the action on this thread. if (canInlineContinuationTask && _syncContext == SynchronizationContext.Current) { RunCallback(GetInvokeActionCallback(), Action, ref Task.InternalCurrent); } else { // Otherwise, Post the action back to the SynchronizationContext. RunCallback(GetPostActionCallback(), this, ref Task.InternalCurrent); } // Any exceptions will be handled by RunCallback. } /// Calls InvokeOrPostAction(false) on the supplied SynchronizationContextAwaitTaskContinuation. /// The SynchronizationContextAwaitTaskContinuation. [SecurityCritical] private static void PostAction(object state) { var c = (SynchronizationContextAwaitTaskContinuation)state; c._syncContext.Post(_postCallback, c.Action); // s_postCallback is manually cached, as the compiler won't in a SecurityCritical method } /// Gets a cached delegate for the PostAction method. /// /// A delegate for PostAction, which expects a SynchronizationContextAwaitTaskContinuation /// to be passed as state. /// [SecurityCritical] private static ContextCallback GetPostActionCallback() { var callback = _postActionCallback; if (callback == null) { // lazily initialize SecurityCritical delegate _postActionCallback = callback = PostAction; } return callback; } } } #endif