// 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 AsyncEnumerable
{
#if INCLUDE_SYSTEM_LINQ_ASYNCENUMERABLE_DUPLICATES
// https://learn.microsoft.com/en-us/dotnet/api/system.linq.asyncenumerable.containsasync?view=net-9.0-pp
//
// These two overloads are replaced by the single method above, which takes a comparer, but supplies a default
// value of null.
///
/// Determines whether an async-enumerable sequence contains a specified element by using the default equality comparer.
///
/// The type of the elements in the source sequence.
/// An async-enumerable sequence in which to locate a value.
/// The value to locate in the source sequence.
/// The optional cancellation token to be used for cancelling the sequence at any time.
/// An async-enumerable sequence containing a single element determining whether the source sequence contains an element that has the specified value.
/// is null.
/// The return type of this operator differs from the corresponding operator on IEnumerable in order to retain asynchronous behavior.
public static ValueTask ContainsAsync(this IAsyncEnumerable source, TSource value, CancellationToken cancellationToken = default) =>
source is ICollection collection ? new ValueTask(collection.Contains(value)) :
ContainsAsync(source, value, comparer: null, cancellationToken);
///
/// Determines whether an async-enumerable sequence contains a specified element by using a specified System.Collections.Generic.IEqualityComparer{T}.
///
/// The type of the elements in the source sequence.
/// An async-enumerable sequence in which to locate a value.
/// The value to locate in the source sequence.
/// An equality comparer to compare elements.
/// The optional cancellation token to be used for cancelling the sequence at any time.
/// An async-enumerable sequence containing a single element determining whether the source sequence contains an element that has the specified value.
/// or is null.
/// The return type of this operator differs from the corresponding operator on IEnumerable in order to retain asynchronous behavior.
public static ValueTask ContainsAsync(this IAsyncEnumerable source, TSource value, IEqualityComparer? comparer, CancellationToken cancellationToken = default)
{
if (source == null)
throw Error.ArgumentNull(nameof(source));
//
// See https://github.com/dotnet/corefx/pull/25097 for the optimization here.
//
if (comparer == null)
{
return Core(source, value, cancellationToken);
static async ValueTask Core(IAsyncEnumerable source, TSource value, CancellationToken cancellationToken)
{
await foreach (var item in source.WithCancellation(cancellationToken).ConfigureAwait(false))
{
if (EqualityComparer.Default.Equals(item, value))
{
return true;
}
}
return false;
}
}
else
{
return Core(source, value, comparer, cancellationToken);
static async ValueTask Core(IAsyncEnumerable source, TSource value, IEqualityComparer comparer, CancellationToken cancellationToken)
{
await foreach (var item in source.WithCancellation(cancellationToken).ConfigureAwait(false))
{
if (comparer.Equals(item, value))
{
return true;
}
}
return false;
}
}
}
#endif // INCLUDE_SYSTEM_LINQ_ASYNCENUMERABLE_DUPLICATES
}
}