// 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
}
}