|February 8, 2015

Daily Archives: February 8, 2015

.NET Coding

Construct Dynamic Filters with C#

Published by:

Filtering data with C# is pretty straight-forward when using LINQ – you get results with one-liners as

var result=cars.Where(a=>a.carMake=="Fiat" && a.speed>100);

However, we know the filtering properties (carMake and speed) and the filtering conditions (equals with carMake and greater than with speed) in advance. The more interesting case, however, is when we don’t know the filtering properties, their number and the filtering criteria in advance but have to construct them in real time. Consider the case when you have data objects with many properties and allow the user on the front end to filter it according to his/her needs. In this case Dynamic Expression Construction comes to rescue.
LINQ extension methods work with predicates (or anonymous functions). Fortunately, C# provides very powerful api to build Expression trees, which can be compiled to predicates in runtime and passed to the LINQ extension methods afterwards.
Let’s see an example. Suppose that we have a list of cars and we want to filter them dynamically for whatever purpose – here is our Car object

public class Car
        public string Model { get; set; }
        public string Make { get; set; }
        public string CountryOfOrigin { get; set; }
        public string CountryOfProduction { get; set; }

        public int MaxMilesPerHour { get; set; }
        public int NumberOfSeats { get; set; }
        public int MilesPerGallon { get; set; }
        public double WeightInKg { get; set; }

        public decimal BasePrice { get; set; }
        public decimal FullPrice { get; set; }

With 10 properties, we can filter a collection of cars in many possible ways.
Next we need a class that would represent a filter – so we need a property name for comparison, value to be compared to and operation (equal, less than etc). Let’s call it ExpressionFilter

public class ExpressionFilter
        public string PropertyName { get; set; }
        public object Value { get; set; }
        public Comparison Comparison{ get; set; }

Comparison is nothing more than a enum with possible operations

public enum Comparison
        Contains, //for strings
        StartsWith, //for strings
        EndsWith //for strings

Next comes the real thing – we need a class which can take a list of ExpressionFilters, do its thing and return an Expression tree composed of these filters, which we can use as a parameter in any LINQ extension method after compiling it. Let’s have a class that constructs And expression trees. We will call it ConstructAndExpressionTree

public static Expression<Func<T, bool>> ConstructAndExpressionTree<T&gt(List<ExpressionFilter> filters)
            if (filters.Count == 0)
                return null;

            ParameterExpression param = Expression.Parameter(typeof(T), "t");
            Expression exp = null;

            if (filters.Count == 1)
                exp = ExpressionRetriever.GetExpression<T>(param, filters[0]);
                exp = ExpressionRetriever.GetExpression<T>(param, filters[0]);
                for (int i = 1; i < filters.Count; i++)
                    exp = Expression.And(exp, ExpressionRetriever.GetExpression<T>(param, filters[i]));

            return Expression.Lambda<Func<T, bool>>(exp, param);

The class is generic so it can be used with any type. The code is pretty straight-forward -> we start with the ParameterExpression which is the t=> part of the predicate. Then we iterate through the filters and start building the actual expression called exp here. You probably notice that we use a helper method ExpressionRetriever.GetExpression to construct the separate expressions (like a.speed>100), which we stick with Or binary operator aferwards. Here is the code of ExpressionRetriever.GetExpression:

public static class ExpressionRetriever
        private static MethodInfo containsMethod = typeof(string).GetMethod("Contains");
        private static MethodInfo startsWithMethod = typeof(string).GetMethod("StartsWith", new Type[] { typeof(string) });
        private static MethodInfo endsWithMethod = typeof(string).GetMethod("EndsWith", new Type[] { typeof(string) });

        public static Expression GetExpression<T>(ParameterExpression param, ExpressionFilter filter)
            MemberExpression member = Expression.Property(param, filter.PropertyName);
            ConstantExpression constant = Expression.Constant(filter.Value);
            switch (filter.Comparison)
                case Comparison.Equal:
                    return Expression.Equal(member, constant);
                case Comparison.GreaterThan:
                    return Expression.GreaterThan(member, constant);
                case Comparison.GreaterThanOrEqual:
                    return Expression.GreaterThanOrEqual(member, constant);
                case Comparison.LessThan:
                    return Expression.LessThan(member, constant);
                case Comparison.LessThanOrEqual:
                    return Expression.LessThanOrEqual(member, constant);
                case Comparison.NotEqual:
                    return Expression.NotEqual(member, constant);
                case Comparison.Contains:
                    return Expression.Call(member, containsMethod, constant);
                case Comparison.StartsWith:
                    return Expression.Call(member, startsWithMethod, constant);
                case Comparison.EndsWith:
                    return Expression.Call(member, endsWithMethod, constant);
                    return null;

Expression class provides methods for the standard operations as equal, not equal, less than etc. but notice also the last three cases where we use Expression.Call to call the string methods Contains, StartsWith and EndsWith. Here lies a big potential for extension as you can use whatever methods you like defined on any type. You only should get their MethodInfo through reflection.
So sticking it all together (i skip the part where i populate the cars collection):

      static void Main(string[] args)
            var filters = new List<ExpressionFilter> 
                new ExpressionFilter
                new ExpressionFilter

            var expressionTree= ExpressionBuilderHelper.ExpressionBuilder.ConstructAndExpressionTree<Car>(filters);
            var anonymousFunc = expressionTree.Compile();
            var result = cars.Where(anonymousFunc);

You can see that the result is a car that has MaxMilesPerHour>190 and CountryOfOrigin that starts with ‘Fr’