Skip to content

Instantly share code, notes, and snippets.

@pedropombeiro
Created November 1, 2016 09:44
Show Gist options
  • Save pedropombeiro/b2b8beb1d2e6b5fdcfa62b3d9e4b52bb to your computer and use it in GitHub Desktop.
Save pedropombeiro/b2b8beb1d2e6b5fdcfa62b3d9e4b52bb to your computer and use it in GitHub Desktop.
SwitchOnDispatcher
using System;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
namespace DeveloperOnTheFlow
{
public struct DispatcherSwitchTaskAwaitable
{
readonly ConfiguredTaskAwaiter configuredTaskAwaiter;
public DispatcherSwitchTaskAwaitable(Task task, SynchronizationContext synchronizationContext)
{
this.configuredTaskAwaiter = new ConfiguredTaskAwaiter(task, synchronizationContext);
}
public class ConfiguredTaskAwaiter : INotifyCompletion
{
#region Fields
readonly SynchronizationContext synchronizationContext;
readonly Task task;
#endregion
#region Constructors
public ConfiguredTaskAwaiter(Task task, SynchronizationContext synchronizationContext)
{
this.task = task;
this.synchronizationContext = synchronizationContext;
}
#endregion
#region Properties, Indexers
/// <summary>
/// Returns true if the task is completed and there is no need for the compiler to call <see cref="OnCompleted"/>. This only happens if we're already on the dispatcher thread, otherwise we want <see cref="OnCompleted"/> to run so we can switch threads.
/// </summary>
public bool IsCompleted => this.task.IsCompleted && SynchronizationContext.Current == this.synchronizationContext;
#endregion
#region Public Methods
/// <summary>Ends the await on the completed <see cref="System.Threading.Tasks.Task"/>.</summary>
/// <returns>The result of the completed <see cref="System.Threading.Tasks.Task{TResult}"/>.</returns>
/// <exception cref="System.NullReferenceException">The awaiter was not properly initialized.</exception>
/// <exception cref="System.Threading.Tasks.TaskCanceledException">The task was canceled.</exception>
/// <exception cref="System.Exception">The task completed in a Faulted state.</exception>
public void GetResult()
{
this.task.Wait();
}
#endregion
#region INotifyCompletion Members
public void OnCompleted(Action continuation)
{
this.synchronizationContext.Post(state => continuation(), null);
}
#endregion
}
/// <summary>Gets an awaiter for this awaitable.</summary>
/// <returns>The awaiter.</returns>
public ConfiguredTaskAwaiter GetAwaiter()
{
return this.configuredTaskAwaiter;
}
}
public struct DispatcherSwitchTaskAwaitable<TResult>
{
readonly ConfiguredTaskAwaiter configuredTaskAwaiter;
public DispatcherSwitchTaskAwaitable(Task<TResult> task, SynchronizationContext synchronizationContext)
{
this.configuredTaskAwaiter = new ConfiguredTaskAwaiter(task, synchronizationContext);
}
public class ConfiguredTaskAwaiter : INotifyCompletion
{
#region Fields
readonly SynchronizationContext synchronizationContext;
readonly Task<TResult> task;
#endregion
#region Constructors
public ConfiguredTaskAwaiter(Task<TResult> task, SynchronizationContext synchronizationContext)
{
this.task = task;
this.synchronizationContext = synchronizationContext;
}
#endregion
#region Properties, Indexers
/// <summary>
/// Returns true if the task is completed and there is no need for the compiler to call <see cref="OnCompleted"/>. This only happens if we're already on the dispatcher thread, otherwise we want <see cref="OnCompleted"/> to run so we can switch threads.
/// </summary>
public bool IsCompleted => this.task.IsCompleted && SynchronizationContext.Current == this.synchronizationContext;
#endregion
#region Public Methods
/// <summary>Ends the await on the completed <see cref="System.Threading.Tasks.Task"/>.</summary>
/// <returns>The result of the completed <see cref="System.Threading.Tasks.Task{TResult}"/>.</returns>
/// <exception cref="System.NullReferenceException">The awaiter was not properly initialized.</exception>
/// <exception cref="System.Threading.Tasks.TaskCanceledException">The task was canceled.</exception>
/// <exception cref="System.Exception">The task completed in a Faulted state.</exception>
public TResult GetResult()
{
return this.task.Result;
}
#endregion
#region INotifyCompletion Members
public void OnCompleted(Action continuation)
{
this.synchronizationContext.Post(state => continuation(), null);
}
#endregion
}
/// <summary>Gets an awaiter for this awaitable.</summary>
/// <returns>The awaiter.</returns>
public ConfiguredTaskAwaiter GetAwaiter()
{
return this.configuredTaskAwaiter;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment