#if NET20 || NET30 || NET35 || NET40 || !NET_4_6 // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. using System.Collections.Generic; using System.ComponentModel; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; namespace System.Threading.Tasks { /// /// Provides a value type that wraps a and a , /// only one of which is used. /// /// The type of the result. /// /// /// Methods may return an instance of this value type when it's likely that the result of their /// operations will be available synchronously and when the method is expected to be invoked so /// frequently that the cost of allocating a new for each call will /// be prohibitive. /// /// /// There are tradeoffs to using a instead of a . /// For example, while a can help avoid an allocation in the case where the /// successful result is available synchronously, it also contains two fields whereas a /// as a reference type is a single field. This means that a method call ends up returning two fields worth of /// data instead of one, which is more data to copy. It also means that if a method that returns one of these /// is awaited within an async method, the state machine for that async method will be larger due to needing /// to store the struct that's two fields instead of a single reference. /// /// /// Further, for uses other than consuming the result of an asynchronous operation via await, /// can lead to a more convoluted programming model, which can in turn actually /// lead to more allocations. For example, consider a method that could return either a /// with a cached task as a common result or a . If the consumer of the result /// wants to use it as a , such as to use with in methods like Task.WhenAll and Task.WhenAny, /// the would first need to be converted into a using /// , which leads to an allocation that would have been avoided if a cached /// had been used in the first place. /// /// /// As such, the default choice for any asynchronous method should be to return a or /// . Only if performance analysis proves it worthwhile should a /// be used instead of . There is no non-generic version of /// as the Task.CompletedTask property may be used to hand back a successfully completed singleton in the case where /// a -returning method completes synchronously and successfully. /// /// [AsyncMethodBuilder(typeof(AsyncValueTaskMethodBuilder<>))] [StructLayout(LayoutKind.Auto)] public struct ValueTask : IEquatable> { /// The task to be used if the operation completed asynchronously or if it completed synchronously but non-successfully. internal readonly Task _task; /// The result to be used if the operation completed successfully synchronously. internal readonly TResult _result; /// Initialize the with the result of the successful operation. /// The result. public ValueTask(TResult result) { _task = null; _result = result; } /// /// Initialize the with a that represents the operation. /// /// The task. public ValueTask(Task task) { if (task == null) { throw new ArgumentNullException("task"); } _task = task; _result = default(TResult); } /// Returns the hash code for this instance. public override int GetHashCode() { return _task != null ? _task.GetHashCode() : !ReferenceEquals(_result, null) ? _result.GetHashCode() : 0; } /// Returns a value indicating whether this value is equal to a specified . public override bool Equals(object obj) { return obj is ValueTask && Equals((ValueTask)obj); } /// Returns a value indicating whether this value is equal to a specified value. public bool Equals(ValueTask other) { return _task != null || other._task != null ? _task == other._task : EqualityComparer.Default.Equals(_result, other._result); } /// Returns a value indicating whether two values are equal. public static bool operator ==(ValueTask left, ValueTask right) { return left.Equals(right); } /// Returns a value indicating whether two values are not equal. public static bool operator !=(ValueTask left, ValueTask right) { return !left.Equals(right); } /// /// Gets a object to represent this ValueTask. It will /// either return the wrapped task object if one exists, or it'll manufacture a new /// task object to represent the result. /// public Task AsTask() { // Return the task if we were constructed from one, otherwise manufacture one. We don't // cache the generated task into _task as it would end up changing both equality comparison // and the hash code we generate in GetHashCode. return _task ?? TaskEx.FromResult(_result); } /// Gets whether the represents a completed operation. public bool IsCompleted { get { return _task == null || _task.IsCompleted; } } /// Gets whether the represents a successfully completed operation. public bool IsCompletedSuccessfully { get { return _task == null || _task.Status == TaskStatus.RanToCompletion; } } /// Gets whether the represents a failed operation. public bool IsFaulted { get { return _task != null && _task.IsFaulted; } } /// Gets whether the represents a canceled operation. public bool IsCanceled { get { return _task != null && _task.IsCanceled; } } /// Gets the result. public TResult Result { get { return _task == null ? _result : _task.GetAwaiter().GetResult(); } } /// Gets an awaiter for this value. public ValueTaskAwaiter GetAwaiter() { return new ValueTaskAwaiter(this); } /// Configures an awaiter for this value. /// /// true to attempt to marshal the continuation back to the captured context; otherwise, false. /// public ConfiguredValueTaskAwaitable ConfigureAwait(bool continueOnCapturedContext) { return new ConfiguredValueTaskAwaitable(this, continueOnCapturedContext: continueOnCapturedContext); } /// Gets a string-representation of this . public override string ToString() { if (_task != null) { return _task.Status == TaskStatus.RanToCompletion && !ReferenceEquals(_task.Result, null) ? _task.Result.ToString() : string.Empty; } return !ReferenceEquals(_result, null) ? _result.ToString() : string.Empty; } // TODO: Remove CreateAsyncMethodBuilder once the C# compiler relies on the AsyncBuilder attribute. /// Creates a method builder for use with an async method. /// The created builder. [EditorBrowsable(EditorBrowsableState.Never)] // intended only for compiler consumption public static AsyncValueTaskMethodBuilder CreateAsyncMethodBuilder() { return AsyncValueTaskMethodBuilder.Create(); } } } #endif