#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