Exemplo n.º 1
0
        /// <summary>
        /// Takes two expressions, func (S -> T -> S) and seed (S), and an enumerable with elements
        /// of type T, and aggregates (aka folds) the elements to produce a valid of type S.
        /// </summary>
        /// <param name="expression">The enumerable to aggregate.</param>
        /// <param name="func">The aggregator function.</param>
        /// <param name="seed">The initial state used when aggregating.</param>
        /// <returns>An expression representing the calculation of the aggregation.</returns>
        public static Expression Aggregate(this EnumerableExpression expression, LambdaExpression func, Expression seed)
        {
            ParameterExpression accVar = Expression.Variable(seed.Type, "acc");

            return(Expression.Block(
                       new[] { accVar },
                       Expression.Assign(accVar, seed),
                       expression.AggregateRaw(e => Expression.Assign(accVar, func.Substitute(accVar, e))),
                       accVar));
        }
Exemplo n.º 2
0
        /// <summary>
        /// Takes an IEnumerable{T}, a lambda of T -> IEnumerable{U} and returns an IEnumerable{U}.
        /// This is also known as a flatmap.
        /// </summary>
        /// <param name="enumerable">The original enumerable to flatmap.</param>
        /// <param name="selector">The flatmapper function.</param>
        /// <returns>The flatmapped enumerable.</returns>
        public static EnumerableExpression SelectMany(this EnumerableExpression enumerable, LambdaExpression selector)
        {
            Type newType = selector.ReturnType.GetIEnumerableElementType();

            EnumerableExpression ToEnumerableExpresion(Expression expr)
            {
                return(expr.Type.IsArray
                    ? OfArray(expr, newType)
                    : OfEnumerable(expr, newType));
            }

            return(enumerable.SelectManyRaw(elem => ToEnumerableExpresion(selector.Substitute(elem)), newType));
        }
Exemplo n.º 3
0
        /// <summary>
        /// Takes a lambda expression that maps the elements of the enumerable and returns an
        /// enumerable of the elements after they were mapped.
        /// </summary>
        /// <param name="expression">The enumerable expression.</param>
        /// <param name="selector">The mapping function.</param>
        /// <returns>The enumerable after mapping.</returns>
        public static EnumerableExpression Select(this EnumerableExpression expression, LambdaExpression selector)
        {
            Func <ParameterExpression, Expression> SelectorBody(Func <ParameterExpression, Expression> continuation)
            {
                Expression Inner(ParameterExpression curElem)
                {
                    ParameterExpression newElemVar = Expression.Variable(selector.ReturnType, "newElem");

                    return(Expression.Block(
                               new[] { newElemVar },
                               Expression.Assign(newElemVar, selector.Substitute(curElem)),
                               continuation(newElemVar)));
                }

                return(Inner);
            }

            return(expression.SelectRaw(SelectorBody, selector.ReturnType));
        }
Exemplo n.º 4
0
 /// <summary>
 /// Takes a selector and uses it to map the elements of an enumerable.
 /// expression : Expression{IQueryable{T}}.
 /// selector : ((Expression{U} -> Expression{void}) -> (Expression{T} -> Expression{void})).
 /// returns : Expression{IQueryable{U}}.
 ///
 /// The selector takes a continuation that handles new elements and returns a continuation
 /// that takes old elements, gets the new element, and passes it into that continuation.
 /// </summary>
 /// <param name="expression">The enumerable expression to map.</param>
 /// <param name="selector">The mapping function.</param>
 /// <param name="newElementType">The new type of the enumerable.</param>
 /// <returns>The new mapped enumerable.</returns>
 private static EnumerableExpression SelectRaw(
     this EnumerableExpression expression,
     Func <Func <ParameterExpression, Expression>, Func <ParameterExpression, Expression> > selector,
     Type newElementType)
 {
     return(expression switch
     {
         LinearEnumerableExpression linear =>
         new LinearEnumerableExpression(
             linear.Initialize,
             linear.HasNext,
             c => linear.MoveNext(selector(c)),
             newElementType),
         NestedEnumerableExpression nested =>
         new NestedEnumerableExpression(
             nested.BaseEnumerable,
             e => nested.GetNestedEnumerable(e).SelectRaw(selector, newElementType),
             newElementType),
         _ => throw new ArgumentException("Must be a linear or nested enumerable.", nameof(expression)),
     });
Exemplo n.º 5
0
 /// <summary>
 /// Takes an enumerable of element T, and an expression from T -> bool, and filters the
 /// enumerable to elements where the predicate is true.
 /// </summary>
 /// <param name="expression">The enumerable to filter.</param>
 /// <param name="predicate">The predicate to filter on.</param>
 /// <returns>The filtered enumerable.</returns>
 public static EnumerableExpression Where(this EnumerableExpression expression, LambdaExpression predicate)
 {
     return(expression.SelectRaw(
                k => cur => Expression.IfThen(predicate.Substitute(cur), k(cur)),
                expression.ElementType));
 }