Last active
August 22, 2022 09:38
-
-
Save theodorzoulias/39d63727dd17e704ddd79c64e7916897 to your computer and use it in GitHub Desktop.
AsyncCollapseConcurrent<TResult> -- https://stackoverflow.com/a/73442817/11178549
This file contains hidden or 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
/// <summary> | |
/// Represents an asynchronous operation that is invoked lazily on demand, can be | |
/// invoked multiple times, and is subject to a non-concurrent execution policy. | |
/// Concurrent observers receive the result of the same operation. | |
/// </summary> | |
public class AsyncCollapseConcurrent<TResult> | |
{ | |
private readonly Func<Task<TResult>> _taskFactory; | |
private volatile Task<TResult> _task; | |
public AsyncCollapseConcurrent(Func<Task<TResult>> taskFactory) | |
{ | |
ArgumentNullException.ThrowIfNull(taskFactory); | |
_taskFactory = taskFactory; | |
} | |
public Task<TResult> Task | |
{ | |
get | |
{ | |
Task<TResult> capturedTask = _task; | |
if (capturedTask is not null) return capturedTask; | |
Task<Task<TResult>> newTaskTask = new(_taskFactory); | |
Task<TResult> newTask = newTaskTask.Unwrap().ContinueWith(t => | |
{ | |
_task = null; | |
return t; | |
}, default, TaskContinuationOptions.DenyChildAttach | | |
TaskContinuationOptions.ExecuteSynchronously, | |
TaskScheduler.Default).Unwrap(); | |
capturedTask = Interlocked | |
.CompareExchange(ref _task, newTask, null) ?? newTask; | |
if (ReferenceEquals(capturedTask, newTask)) | |
newTaskTask.RunSynchronously(TaskScheduler.Default); | |
return capturedTask; | |
} | |
} | |
public TaskAwaiter<TResult> GetAwaiter() => Task.GetAwaiter(); | |
public ConfiguredTaskAwaitable<TResult> ConfigureAwait( | |
bool continueOnCapturedContext) | |
=> Task.ConfigureAwait(continueOnCapturedContext); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment