Răsfoiți Sursa

Fix ToEnumerable's use of ValueTask.

Bart De Smet 7 ani în urmă
părinte
comite
92515218cc

+ 35 - 3
Ix.NET/Source/System.Linq.Async/System/Linq/Operators/ToEnumerable.cs

@@ -3,11 +3,15 @@
 // See the LICENSE file in the project root for more information. 
 
 using System.Collections.Generic;
+using System.Threading.Tasks;
 
 namespace System.Linq
 {
     public static partial class AsyncEnumerable
     {
+        // REVIEW: This type of blocking is an anti-pattern. We may want to move it to System.Interactive.Async
+        //         and remove it from System.Linq.Async API surface.
+
         public static IEnumerable<TSource> ToEnumerable<TSource>(this IAsyncEnumerable<TSource> source)
         {
             if (source == null)
@@ -23,7 +27,7 @@ namespace System.Linq
                 {
                     while (true)
                     {
-                        if (!e.MoveNextAsync().GetAwaiter().GetResult())
+                        if (!Wait(e.MoveNextAsync()))
                             break;
 
                         yield return e.Current;
@@ -31,10 +35,38 @@ namespace System.Linq
                 }
                 finally
                 {
-                    // Wait
-                    e.DisposeAsync().GetAwaiter().GetResult();
+                    Wait(e.DisposeAsync());
                 }
             }
         }
+
+        // NB: ValueTask and ValueTask<T> do not have to support blocking on a call to GetResult when backed by
+        //     an IValueTaskSource or IValueTaskSource<T> implementation. Convert to a Task or Task<T> to do so
+        //     in case the task hasn't completed yet.
+
+        private static void Wait(ValueTask task)
+        {
+            var awaiter = task.GetAwaiter();
+
+            if (!awaiter.IsCompleted)
+            {
+                task.AsTask().GetAwaiter().GetResult();
+                return;
+            }
+
+            awaiter.GetResult();
+        }
+
+        private static T Wait<T>(ValueTask<T> task)
+        {
+            var awaiter = task.GetAwaiter();
+
+            if (!awaiter.IsCompleted)
+            {
+                return task.AsTask().GetAwaiter().GetResult();
+            }
+
+            return awaiter.GetResult();
+        }
     }
 }