// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the Apache 2.0 License. // 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. /// /// Converts an async-enumerable sequence to an enumerable sequence. /// /// The type of the elements in the source sequence. /// An async-enumerable sequence to convert to an enumerable sequence. /// The enumerable sequence containing the elements in the async-enumerable sequence. /// is null. public static IEnumerable ToEnumerable(this IAsyncEnumerable source) { if (source == null) throw Error.ArgumentNull(nameof(source)); return Core(source); static IEnumerable Core(IAsyncEnumerable source) { var e = source.GetAsyncEnumerator(default); try { while (true) { if (!Wait(e.MoveNextAsync())) break; yield return e.Current; } } finally { Wait(e.DisposeAsync()); } } } // NB: ValueTask and ValueTask do not have to support blocking on a call to GetResult when backed by // an IValueTaskSource or IValueTaskSource implementation. Convert to a Task or Task 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(ValueTask task) { var awaiter = task.GetAwaiter(); if (!awaiter.IsCompleted) { return task.AsTask().GetAwaiter().GetResult(); } return awaiter.GetResult(); } } }