|
@@ -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();
|
|
|
+ }
|
|
|
}
|
|
|
}
|