#if NET20 || NET30 || NET35 || NET40 || !NET_4_6
using System.Diagnostics;
using System.Security;
using System.Threading.Tasks;
namespace System.Runtime.CompilerServices
{
///
/// Provides a builder for asynchronous methods that return .
/// This type is intended for compiler use only.
///
///
///
///
/// AsyncTaskMethodBuilder is a value type, and thus it is copied by value.
/// Prior to being copied, one of its Task, SetResult, or SetException members must be accessed,
/// or else the copies may end up building distinct Task instances.
///
///
public struct AsyncTaskMethodBuilder : IAsyncMethodBuilder
{
///
/// A cached VoidTaskResult task used for builders that complete synchronously.
///
private static readonly TaskCompletionSource _cachedCompleted = AsyncTaskMethodBuilder._defaultResultTask;
///
/// The generic builder object to which this non-generic instance delegates.
///
private AsyncTaskMethodBuilder _builder;
///
/// Gets the for this builder.
///
///
///
/// The representing the builder's asynchronous operation.
///
/// The builder is not initialized.
public Task Task
{
get { return _builder.Task; }
}
///
/// Gets an object that may be used to uniquely identify this builder to the debugger.
///
///
///
///
/// This property lazily instantiates the ID in a non-thread-safe manner.
/// It must only be used by the debugger, and only in a single-threaded manner
/// when no other threads are in the middle of accessing this property or this.Task.
///
///
private object ObjectIdForDebugger
{
get { return Task; }
}
///
/// Initializes a new .
///
///
///
/// The initialized .
///
public static AsyncTaskMethodBuilder Create()
{
return new AsyncTaskMethodBuilder();
}
///
/// Initiates the builder's execution with the associated state machine.
///
/// Specifies the type of the state machine.The state machine instance, passed by reference.
[DebuggerStepThrough]
public void Start(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine
{
_builder.Start(ref stateMachine);
}
///
/// Associates the builder with the state machine it represents.
///
/// The heap-allocated state machine object.The argument was null (Nothing in Visual Basic).The builder is incorrectly initialized.
public void SetStateMachine(IAsyncStateMachine stateMachine)
{
_builder.SetStateMachine(stateMachine);
}
void IAsyncMethodBuilder.PreBoxInitialization()
{
GC.KeepAlive(Task);
}
///
/// Schedules the specified state machine to be pushed forward when the specified awaiter completes.
///
///
/// Specifies the type of the awaiter.Specifies the type of the state machine.The awaiter.The state machine.
public void AwaitOnCompleted(ref TAwaiter awaiter, ref TStateMachine stateMachine)
where TAwaiter : INotifyCompletion
where TStateMachine : IAsyncStateMachine
{
_builder.AwaitOnCompleted(ref awaiter, ref stateMachine);
}
///
/// Schedules the specified state machine to be pushed forward when the specified awaiter completes.
///
///
/// Specifies the type of the awaiter.Specifies the type of the state machine.The awaiter.The state machine.
public void AwaitUnsafeOnCompleted(ref TAwaiter awaiter, ref TStateMachine stateMachine)
where TAwaiter : ICriticalNotifyCompletion
where TStateMachine : IAsyncStateMachine
{
_builder.AwaitUnsafeOnCompleted(ref awaiter, ref stateMachine);
}
///
/// Completes the in the
/// RanToCompletion state.
///
///
/// The builder is not initialized.The task has already completed.
public void SetResult()
{
_builder.SetResult(_cachedCompleted);
}
///
/// Completes the in the
/// Faulted state with the specified exception.
///
///
/// The to use to fault the task.The argument is null (Nothing in Visual Basic).The builder is not initialized.The task has already completed.
public void SetException(Exception exception)
{
_builder.SetException(exception);
}
///
/// Called by the debugger to request notification when the first wait operation
/// (await, Wait, Result, etc.) on this builder's task completes.
///
///
/// true to enable notification; false to disable a previously set notification.
///
internal void SetNotificationForWaitCompletion(bool enabled)
{
_builder.SetNotificationForWaitCompletion(enabled);
}
}
///
/// Provides a builder for asynchronous methods that return .
/// This type is intended for compiler use only.
///
///
///
///
/// AsyncTaskMethodBuilder{TResult} is a value type, and thus it is copied by value.
/// Prior to being copied, one of its Task, SetResult, or SetException members must be accessed,
/// or else the copies may end up building distinct Task instances.
///
///
public struct AsyncTaskMethodBuilder : IAsyncMethodBuilder
{
///
/// A cached task for default(TResult).
///
internal static readonly TaskCompletionSource _defaultResultTask = AsyncMethodTaskCache.CreateCompleted(default(TResult));
///
/// State related to the IAsyncStateMachine.
///
private AsyncMethodBuilderCore _coreState;
///
/// The lazily-initialized task completion source.
///
private TaskCompletionSource _task;
///
/// Gets the lazily-initialized TaskCompletionSource.
///
internal TaskCompletionSource CompletionSource
{
get
{
var completionSource = _task;
if (completionSource == null)
{
_task = completionSource = new TaskCompletionSource();
}
return completionSource;
}
}
///
/// Gets the for this builder.
///
///
///
/// The representing the builder's asynchronous operation.
///
public Task Task
{
get { return CompletionSource.Task; }
}
///
/// Gets an object that may be used to uniquely identify this builder to the debugger.
///
///
///
///
/// This property lazily instantiates the ID in a non-thread-safe manner.
/// It must only be used by the debugger, and only in a single-threaded manner
/// when no other threads are in the middle of accessing this property or this.Task.
///
///
private object ObjectIdForDebugger
{
get { return Task; }
}
///
/// Temporary support for disabling crashing if tasks go unobserved.
///
static AsyncTaskMethodBuilder()
{
try
{
AsyncVoidMethodBuilder.PreventUnobservedTaskExceptions();
}
catch (Exception ex)
{
GC.KeepAlive(ex);
}
}
///
/// Initializes a new .
///
///
///
/// The initialized .
///
public static AsyncTaskMethodBuilder Create()
{
return new AsyncTaskMethodBuilder();
}
///
/// Initiates the builder's execution with the associated state machine.
///
/// Specifies the type of the state machine.The state machine instance, passed by reference.
[DebuggerStepThrough]
public void Start(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine
{
_coreState.Start(ref stateMachine);
}
///
/// Associates the builder with the state machine it represents.
///
/// The heap-allocated state machine object.The argument was null (Nothing in Visual Basic).The builder is incorrectly initialized.
public void SetStateMachine(IAsyncStateMachine stateMachine)
{
_coreState.SetStateMachine(stateMachine);
}
void IAsyncMethodBuilder.PreBoxInitialization()
{
GC.KeepAlive(Task);
}
///
/// Schedules the specified state machine to be pushed forward when the specified awaiter completes.
///
///
/// Specifies the type of the awaiter.Specifies the type of the state machine.The awaiter.The state machine.
public void AwaitOnCompleted(ref TAwaiter awaiter, ref TStateMachine stateMachine)
where TAwaiter : INotifyCompletion
where TStateMachine : IAsyncStateMachine
{
try
{
var completionAction = _coreState.GetCompletionAction(ref this, ref stateMachine);
awaiter.OnCompleted(completionAction);
}
catch (Exception ex)
{
AsyncMethodBuilderCore.ThrowOnContext(ex, null);
}
}
///
/// Schedules the specified state machine to be pushed forward when the specified awaiter completes.
///
///
/// Specifies the type of the awaiter.Specifies the type of the state machine.The awaiter.The state machine.
[SecuritySafeCritical]
public void AwaitUnsafeOnCompleted(ref TAwaiter awaiter, ref TStateMachine stateMachine)
where TAwaiter : ICriticalNotifyCompletion
where TStateMachine : IAsyncStateMachine
{
try
{
var completionAction = _coreState.GetCompletionAction(ref this, ref stateMachine);
awaiter.UnsafeOnCompleted(completionAction);
}
catch (Exception ex)
{
AsyncMethodBuilderCore.ThrowOnContext(ex, null);
}
}
///
/// Completes the in the
/// RanToCompletion state with the specified result.
///
///
/// The result to use to complete the task.The task has already completed.
public void SetResult(TResult result)
{
var completionSource = _task;
if (completionSource == null)
{
_task = GetTaskForResult(result);
}
else if (!completionSource.TrySetResult(result))
{
throw new InvalidOperationException("The Task was already completed.");
}
}
///
/// Completes the builder by using either the supplied completed task, or by completing
/// the builder's previously accessed task using default(TResult).
///
///
/// A task already completed with the value default(TResult).The task has already completed.
internal void SetResult(TaskCompletionSource completedTask)
{
if (_task == null)
{
_task = completedTask;
}
else
{
SetResult(default(TResult));
}
}
///
/// Completes the in the
/// Faulted state with the specified exception.
///
///
/// The to use to fault the task.The argument is null (Nothing in Visual Basic).The task has already completed.
public void SetException(Exception exception)
{
if (exception == null)
{
throw new ArgumentNullException("exception");
}
var completionSource = CompletionSource;
var setException = (exception is OperationCanceledException ? completionSource.TrySetCanceled() : completionSource.TrySetException(exception));
if (!setException)
{
throw new InvalidOperationException("The Task was already completed.");
}
}
///
/// Called by the debugger to request notification when the first wait operation
/// (await, Wait, Result, etc.) on this builder's task completes.
///
///
/// true to enable notification; false to disable a previously set notification.
///
///
/// This should only be invoked from within an asynchronous method,
/// and only by the debugger.
///
///
internal void SetNotificationForWaitCompletion(bool enabled)
{
GC.KeepAlive(enabled);
}
///
/// Gets a task for the specified result. This will either
/// be a cached or new task, never null.
///
///
/// The result for which we need a task.
///
/// The completed task containing the result.
///
private TaskCompletionSource GetTaskForResult(TResult result)
{
var asyncMethodTaskCache = AsyncMethodTaskCache.Singleton;
if (asyncMethodTaskCache == null)
{
return AsyncMethodTaskCache.CreateCompleted(result);
}
return asyncMethodTaskCache.FromResult(result);
}
}
}
#endif