/* * QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals. * Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; namespace QuantConnect.Util { /// /// Provides methods for constructing expressions at runtime /// public static class ExpressionBuilder { /// /// Constructs a selector of the form: x => x.propertyOrField where x is an instance of 'type' /// /// The type of the parameter in the expression /// The name of the property or field to bind to /// A new lambda expression that represents accessing the property or field on 'type' public static LambdaExpression MakePropertyOrFieldSelector(Type type, string propertyOrField) { var parameter = Expression.Parameter(type); var property = Expression.PropertyOrField(parameter, propertyOrField); var lambda = Expression.Lambda(property, parameter); return lambda; } /// /// Constructs a selector of the form: x => x.propertyOrField where x is an instance of 'type' /// /// The type of the parameter in the expression /// The type of the property or field being accessed in the expression /// The name of the property or field to bind to /// A new lambda expression that represents accessing the property or field on 'type' public static Expression> MakePropertyOrFieldSelector(string propertyOrField) { return (Expression>) MakePropertyOrFieldSelector(typeof (T), propertyOrField); } /// /// Constructs a lambda expression that accepts two parameters of type and applies /// the specified binary comparison and returns the boolean result. /// public static Expression> MakeBinaryComparisonLambda(ExpressionType type) { if (!type.IsBinaryComparison()) { throw new ArgumentException($"Provided ExpressionType '{type}' is not a binary comparison."); } var left = Expression.Parameter(typeof(T), "left"); var right = Expression.Parameter(typeof(T), "right"); var body = Expression.MakeBinary(type, left, right); var lambda = Expression.Lambda>(body, left, right); return lambda; } /// /// Determines whether or not the specified is a binary comparison. /// public static bool IsBinaryComparison(this ExpressionType type) { switch (type) { case ExpressionType.Equal: case ExpressionType.NotEqual: case ExpressionType.LessThan: case ExpressionType.LessThanOrEqual: case ExpressionType.GreaterThan: case ExpressionType.GreaterThanOrEqual: return true; default: return false; } } /// /// Converts the specified expression into an enumerable of expressions by walking the expression tree /// /// The expression to enumerate /// An enumerable containing all expressions in the input expression public static IEnumerable AsEnumerable(this Expression expression) { var walker = new ExpressionWalker(); walker.Visit(expression); return walker.Expressions; } /// /// Returns all the expressions of the specified type in the given expression tree /// /// The type of expression to search for /// The expression to search /// All expressions of the given type in the specified expression public static IEnumerable OfType(this Expression expression) where T : Expression { return expression.AsEnumerable().OfType(); } /// /// Returns the single expression of the specified type or throws if none or more than one expression /// of the specified type is contained within the expression. /// /// The type of expression to search for /// The expression to search /// Expression of the specified type public static T Single(this Expression expression) where T : Expression { return expression.AsEnumerable().OfType().Single(); } /// /// Returns the single expression of the specified type or throws if none or more than one expression /// of the specified type is contained within the expression. /// /// The type of expression to search for /// The expressions to search /// Expression of the specified type public static T Single(this IEnumerable expressions) where T : Expression { return expressions.OfType().Single(); } private class ExpressionWalker : ExpressionVisitor { public readonly HashSet Expressions = new HashSet(); public override Expression Visit(Expression node) { Expressions.Add(node); return base.Visit(node); } } } }