// 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.Linq.Expressions; using System.Threading; using System.Threading.Tasks; namespace System.Linq { /// /// Representation of an asynchronous enumerable sequence using an expression tree. /// internal abstract class AsyncEnumerableQuery { /// /// Gets the enumerable sequence obtained from evaluating the expression tree. /// internal abstract object? Enumerable { get; } /// /// Gets the expression tree representing the asynchronous enumerable sequence. /// internal abstract Expression Expression { get; } } /// /// Representation of an asynchronous enumerable sequence using an expression tree. /// /// The type of the elements in the sequence. internal class AsyncEnumerableQuery : AsyncEnumerableQuery, IOrderedAsyncQueryable, IAsyncQueryProvider { private readonly Expression _expression; private IAsyncEnumerable? _enumerable; /// /// Creates a new asynchronous enumerable sequence represented by the specified expression tree. /// /// The expression tree representing the asynchronous enumerable sequence. public AsyncEnumerableQuery(Expression expression) { _expression = expression; } /// /// Creates a new asynchronous enumerable sequence by wrapping the specified sequence in an expression tree representation. /// /// The asynchronous enumerable sequence to represent using an expression tree. public AsyncEnumerableQuery(IAsyncEnumerable enumerable) { _enumerable = enumerable; _expression = Expression.Constant(this); } /// /// Gets the type of the elements in the sequence. /// Type IAsyncQueryable.ElementType => typeof(T); /// /// Gets the expression representing the sequence. /// Expression IAsyncQueryable.Expression => _expression; /// /// Gets the query provider used to execute the sequence. /// IAsyncQueryProvider IAsyncQueryable.Provider => this; /// /// Gets the enumerable sequence obtained from evaluating the expression tree. /// internal override object? Enumerable => _enumerable; /// /// Gets the expression tree representing the asynchronous enumerable sequence. /// internal override Expression Expression => _expression; /// /// Creates a new asynchronous enumerable sequence represented by an expression tree. /// /// The type of the elements in the sequence. /// The expression tree representing the asynchronous enumerable sequence. /// Asynchronous enumerable sequence represented by the specified expression tree. IAsyncQueryable IAsyncQueryProvider.CreateQuery(Expression expression) { return new AsyncEnumerableQuery(expression); } /// /// Executes an expression tree representing a computation over asynchronous enumerable sequences. /// /// The type of the result of evaluating the expression tree. /// The expression tree to evaluate. /// Cancellation token used to cancel the evaluation. /// Task representing the result of evaluating the specified expression tree. ValueTask IAsyncQueryProvider.ExecuteAsync(Expression expression, CancellationToken token) { if (expression == null) { throw new ArgumentNullException(nameof(expression)); } if (!typeof(ValueTask).IsAssignableFrom(expression.Type)) { throw new ArgumentException("The specified expression is not assignable to the result type.", nameof(expression)); } return new AsyncEnumerableExecutor(expression).ExecuteAsync(token); } /// /// Gets an enumerator to enumerate the elements in the sequence. /// /// Cancellation token used to cancel the enumeration. /// A new enumerator instance used to enumerate the elements in the sequence. public IAsyncEnumerator GetAsyncEnumerator(CancellationToken token) { token.ThrowIfCancellationRequested(); if (_enumerable == null) { var expression = Expression.Lambda>>(new AsyncEnumerableRewriter().Visit(_expression), null); _enumerable = expression.Compile()(); } return _enumerable.GetAsyncEnumerator(token); } /// /// Gets a string representation of the enumerable sequence. /// /// String representation of the enumerable sequence. public override string ToString() { if (!(_expression is ConstantExpression ce) || ce.Value != this) { return _expression.ToString(); } if (_enumerable != null) { return _enumerable.ToString(); } return "null"; } } }