// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license 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; } // TODO: non-generic interface? /// /// 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 { get { return typeof(T); } } /// /// Gets the expression representing the sequence. /// Expression IAsyncQueryable.Expression { get { return _expression; } } /// /// Gets the query provider used to execute the sequence. /// IAsyncQueryProvider IAsyncQueryable.Provider { get { return this; } } /// /// Gets the enumerable sequence obtained from evaluating the expression tree. /// internal override object Enumerable { get { return _enumerable; } } /// /// Gets the expression tree representing the asynchronous enumerable sequence. /// internal override Expression Expression { get { return _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. Task IAsyncQueryProvider.ExecuteAsync(Expression expression, CancellationToken token) { if (expression == null) { throw new ArgumentNullException("expression"); } if (!typeof(Task).IsAssignableFrom(expression.Type)) { throw new ArgumentException("The specified expression is not assignable to the result type.", "expression"); } return new AsyncEnumerableExecutor(expression).ExecuteAsync(token); } /// /// Gets an enumerator to enumerate the elements in the sequence. /// /// A new enumerator instance used to enumerate the elements in the sequence. public IAsyncEnumerator GetEnumerator() { if (_enumerable == null) { var expression = Expression.Lambda>>(new AsyncEnumerableRewriter().Visit(_expression), null); _enumerable = expression.Compile()(); } return _enumerable.GetEnumerator(); } /// /// Gets a string representation of the enumerable sequence. /// /// String representation of the enumerable sequence. public override string ToString() { var ce = _expression as ConstantExpression; if (ce == null || ce.Value != this) { return _expression.ToString(); } if (_enumerable != null) { return _enumerable.ToString(); } return "null"; } } }