// 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.Threading; using System.Threading.Tasks; namespace System.Linq { public static partial class AsyncEnumerableEx { // REVIEW: Add support for IAsyncDisposable resources. /// /// Constructs an async-enumerable sequence that depends on a resource object, whose lifetime is tied to the resulting async-enumerable sequence's lifetime. /// /// The type of the elements in the produced sequence. /// The type of the resource used during the generation of the resulting sequence. Needs to implement . /// Factory function to obtain a resource object. /// Factory function to obtain an async-enumerable sequence that depends on the obtained resource. /// An async-enumerable sequence whose lifetime controls the lifetime of the dependent resource object. /// or is null. public static IAsyncEnumerable Using(Func resourceFactory, Func> enumerableFactory) where TResource : IDisposable { if (resourceFactory == null) throw Error.ArgumentNull(nameof(resourceFactory)); if (enumerableFactory == null) throw Error.ArgumentNull(nameof(enumerableFactory)); #if HAS_ASYNC_ENUMERABLE_CANCELLATION return Core(resourceFactory, enumerableFactory); static async IAsyncEnumerable Core(Func resourceFactory, Func> enumerableFactory, [System.Runtime.CompilerServices.EnumeratorCancellation]CancellationToken cancellationToken = default) #else return AsyncEnumerable.Create(Core); async IAsyncEnumerator Core(CancellationToken cancellationToken) #endif { using var resource = resourceFactory(); await foreach (var item in enumerableFactory(resource).WithCancellation(cancellationToken).ConfigureAwait(false)) { yield return item; } } } /// /// Constructs an async-enumerable sequence that depends on a resource object, whose lifetime is tied to the resulting async-enumerable sequence's lifetime. /// /// The type of the elements in the produced sequence. /// The type of the resource used during the generation of the resulting sequence. Needs to implement . /// Asynchronous factory function to obtain a resource object. /// Asynchronous factory function to obtain an async-enumerable sequence that depends on the obtained resource. /// An async-enumerable sequence whose lifetime controls the lifetime of the dependent resource object. /// or is null. /// This operator is especially useful in conjunction with the asynchronous programming features introduced in C# 5.0 and Visual Basic 11. /// When a subscription to the resulting sequence is disposed, the CancellationToken that was fed to the asynchronous resource factory and async-enumerable factory functions will be signaled. public static IAsyncEnumerable Using(Func> resourceFactory, Func>> enumerableFactory) where TResource : IDisposable { if (resourceFactory == null) throw Error.ArgumentNull(nameof(resourceFactory)); if (enumerableFactory == null) throw Error.ArgumentNull(nameof(enumerableFactory)); #if HAS_ASYNC_ENUMERABLE_CANCELLATION return Core(resourceFactory, enumerableFactory); static async IAsyncEnumerable Core(Func> resourceFactory, Func>> enumerableFactory, [System.Runtime.CompilerServices.EnumeratorCancellation]CancellationToken cancellationToken = default) #else return AsyncEnumerable.Create(Core); async IAsyncEnumerator Core(CancellationToken cancellationToken) #endif { using var resource = await resourceFactory().ConfigureAwait(false); await foreach (var item in (await enumerableFactory(resource).ConfigureAwait(false)).WithCancellation(cancellationToken).ConfigureAwait(false)) { yield return item; } } } #if !NO_DEEP_CANCELLATION /// /// Constructs an async-enumerable sequence that depends on a resource object, whose lifetime is tied to the resulting async-enumerable sequence's lifetime. The resource is obtained and used through asynchronous methods. /// The CancellationToken passed to the asynchronous methods is tied to the returned disposable subscription, allowing best-effort cancellation at any stage of the resource acquisition or usage. /// /// The type of the elements in the produced sequence. /// The type of the resource used during the generation of the resulting sequence. Needs to implement . /// Asynchronous factory function to obtain a resource object. /// Asynchronous factory function to obtain an async-enumerable sequence that depends on the obtained resource. /// An async-enumerable sequence whose lifetime controls the lifetime of the dependent resource object. /// or is null. /// This operator is especially useful in conjunction with the asynchronous programming features introduced in C# 5.0 and Visual Basic 11. /// When a subscription to the resulting sequence is disposed, the CancellationToken that was fed to the asynchronous resource factory and async-enumerable factory functions will be signaled. public static IAsyncEnumerable Using(Func> resourceFactory, Func>> enumerableFactory) where TResource : IDisposable { if (resourceFactory == null) throw Error.ArgumentNull(nameof(resourceFactory)); if (enumerableFactory == null) throw Error.ArgumentNull(nameof(enumerableFactory)); #if HAS_ASYNC_ENUMERABLE_CANCELLATION return Core(resourceFactory, enumerableFactory); static async IAsyncEnumerable Core(Func> resourceFactory, Func>> enumerableFactory, [System.Runtime.CompilerServices.EnumeratorCancellation]CancellationToken cancellationToken = default) #else return AsyncEnumerable.Create(Core); async IAsyncEnumerator Core(CancellationToken cancellationToken) #endif { using var resource = await resourceFactory(cancellationToken).ConfigureAwait(false); await foreach (var item in (await enumerableFactory(resource, cancellationToken).ConfigureAwait(false)).WithCancellation(cancellationToken).ConfigureAwait(false)) { yield return item; } } } #endif } }