diff options
4 files changed, 40 insertions, 31 deletions
diff --git a/src/mscorlib/shared/System/Runtime/CompilerServices/ConfiguredValueTaskAwaitable.cs b/src/mscorlib/shared/System/Runtime/CompilerServices/ConfiguredValueTaskAwaitable.cs index 4e8ce691be..f22b9d94bf 100644 --- a/src/mscorlib/shared/System/Runtime/CompilerServices/ConfiguredValueTaskAwaitable.cs +++ b/src/mscorlib/shared/System/Runtime/CompilerServices/ConfiguredValueTaskAwaitable.cs @@ -35,10 +35,10 @@ namespace System.Runtime.CompilerServices /// <summary>Provides an awaiter for a <see cref="ConfiguredValueTaskAwaitable{TResult}"/>.</summary> [StructLayout(LayoutKind.Auto)] - public struct ConfiguredValueTaskAwaiter : ICriticalNotifyCompletion, IConfiguredValueTaskAwaiter + public readonly struct ConfiguredValueTaskAwaiter : ICriticalNotifyCompletion, IConfiguredValueTaskAwaiter { /// <summary>The value being awaited.</summary> - private ValueTask<TResult> _value; // Methods are called on this; avoid making it readonly so as to avoid unnecessary copies + private readonly ValueTask<TResult> _value; /// <summary>The value to pass to ConfigureAwait.</summary> internal readonly bool _continueOnCapturedContext; @@ -74,7 +74,11 @@ namespace System.Runtime.CompilerServices /// <summary>Gets the task underlying the incomplete <see cref="_value"/>.</summary> /// <remarks>This method is used when awaiting and IsCompleted returned false; thus we expect the value task to be wrapping a non-null task.</remarks> - (Task task, bool continueOnCapturedContext) IConfiguredValueTaskAwaiter.GetTask() => (_value.AsTaskExpectNonNull(), _continueOnCapturedContext); + Task IConfiguredValueTaskAwaiter.GetTask(out bool continueOnCapturedContext) + { + continueOnCapturedContext = _continueOnCapturedContext; + return _value.AsTaskExpectNonNull(); + } } } @@ -83,6 +87,6 @@ namespace System.Runtime.CompilerServices /// </summary> internal interface IConfiguredValueTaskAwaiter { - (Task task, bool continueOnCapturedContext) GetTask(); + Task GetTask(out bool continueOnCapturedContext); } } diff --git a/src/mscorlib/shared/System/Runtime/CompilerServices/ValueTaskAwaiter.cs b/src/mscorlib/shared/System/Runtime/CompilerServices/ValueTaskAwaiter.cs index 7bc8b5cc7d..3f212d8bf9 100644 --- a/src/mscorlib/shared/System/Runtime/CompilerServices/ValueTaskAwaiter.cs +++ b/src/mscorlib/shared/System/Runtime/CompilerServices/ValueTaskAwaiter.cs @@ -8,10 +8,10 @@ using System.Threading.Tasks; namespace System.Runtime.CompilerServices { /// <summary>Provides an awaiter for a <see cref="ValueTask{TResult}"/>.</summary> - public struct ValueTaskAwaiter<TResult> : ICriticalNotifyCompletion, IValueTaskAwaiter + public readonly struct ValueTaskAwaiter<TResult> : ICriticalNotifyCompletion, IValueTaskAwaiter { /// <summary>The value being awaited.</summary> - private ValueTask<TResult> _value; // Methods are called on this; avoid making it readonly so as to avoid unnecessary copies + private readonly ValueTask<TResult> _value; /// <summary>Initializes the awaiter.</summary> /// <param name="value">The value to be awaited.</param> diff --git a/src/mscorlib/shared/System/Threading/Tasks/ValueTask.cs b/src/mscorlib/shared/System/Threading/Tasks/ValueTask.cs index de9b016328..5edd8501b0 100644 --- a/src/mscorlib/shared/System/Threading/Tasks/ValueTask.cs +++ b/src/mscorlib/shared/System/Threading/Tasks/ValueTask.cs @@ -3,7 +3,6 @@ // 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; @@ -77,7 +76,7 @@ namespace System.Threading.Tasks } _task = task; - _result = default(TResult); + _result = default; } /// <summary>Returns the hash code for this instance.</summary> @@ -114,7 +113,12 @@ namespace System.Threading.Tasks // 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. - _task ?? AsyncTaskMethodBuilder<TResult>.GetTaskForResult(_result); + _task ?? +#if netstandard + Task.FromResult(_result); +#else + AsyncTaskMethodBuilder<TResult>.GetTaskForResult(_result); +#endif internal Task<TResult> AsTaskExpectNonNull() => // Return the task if we were constructed from one, otherwise manufacture one. @@ -123,13 +127,24 @@ namespace System.Threading.Tasks _task ?? GetTaskForResultNoInlining(); [MethodImpl(MethodImplOptions.NoInlining)] - private Task<TResult> GetTaskForResultNoInlining() => AsyncTaskMethodBuilder<TResult>.GetTaskForResult(_result); + private Task<TResult> GetTaskForResultNoInlining() => +#if netstandard + Task.FromResult(_result); +#else + AsyncTaskMethodBuilder<TResult>.GetTaskForResult(_result); +#endif /// <summary>Gets whether the <see cref="ValueTask{TResult}"/> represents a completed operation.</summary> public bool IsCompleted => _task == null || _task.IsCompleted; /// <summary>Gets whether the <see cref="ValueTask{TResult}"/> represents a successfully completed operation.</summary> - public bool IsCompletedSuccessfully => _task == null || _task.IsCompletedSuccessfully; + public bool IsCompletedSuccessfully => + _task == null || +#if netstandard + _task.Status == TaskStatus.RanToCompletion; +#else + _task.IsCompletedSuccessfully; +#endif /// <summary>Gets whether the <see cref="ValueTask{TResult}"/> represents a failed operation.</summary> public bool IsFaulted => _task != null && _task.IsFaulted; @@ -153,26 +168,16 @@ namespace System.Threading.Tasks /// <summary>Gets a string-representation of this <see cref="ValueTask{TResult}"/>.</summary> public override string ToString() { - if (_task != null) + if (IsCompletedSuccessfully) { - return _task.IsCompletedSuccessfully && _task.Result != null ? - _task.Result.ToString() : - string.Empty; + TResult result = Result; + if (result != null) + { + return result.ToString(); + } } - else - { - return _result != null ? - _result.ToString() : - string.Empty; - } - } - // TODO https://github.com/dotnet/corefx/issues/22171: - // Remove CreateAsyncMethodBuilder once the C# compiler relies on the AsyncBuilder attribute. - - /// <summary>Creates a method builder for use with an async method.</summary> - /// <returns>The created builder.</returns> - [EditorBrowsable(EditorBrowsableState.Never)] // intended only for compiler consumption - public static AsyncValueTaskMethodBuilder<TResult> CreateAsyncMethodBuilder() => AsyncValueTaskMethodBuilder<TResult>.Create(); + return string.Empty; + } } } diff --git a/src/mscorlib/src/System/Runtime/CompilerServices/AsyncMethodBuilder.cs b/src/mscorlib/src/System/Runtime/CompilerServices/AsyncMethodBuilder.cs index 30734048c5..022f15ab11 100644 --- a/src/mscorlib/src/System/Runtime/CompilerServices/AsyncMethodBuilder.cs +++ b/src/mscorlib/src/System/Runtime/CompilerServices/AsyncMethodBuilder.cs @@ -413,8 +413,8 @@ namespace System.Runtime.CompilerServices } else if ((null != (object)default(TAwaiter)) && (awaiter is IConfiguredValueTaskAwaiter)) { - (Task task, bool continueOnCapturedContext) t = ((IConfiguredValueTaskAwaiter)awaiter).GetTask(); - TaskAwaiter.UnsafeOnCompletedInternal(t.task, box, t.continueOnCapturedContext); + Task t = ((IConfiguredValueTaskAwaiter)awaiter).GetTask(out bool continueOnCapturedContext); + TaskAwaiter.UnsafeOnCompletedInternal(t, box, continueOnCapturedContext); } // The awaiter isn't specially known. Fall back to doing a normal await. else |