Created
November 1, 2016 09:44
-
-
Save pedropombeiro/b2b8beb1d2e6b5fdcfa62b3d9e4b52bb to your computer and use it in GitHub Desktop.
SwitchOnDispatcher
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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