2

I have to filter a list of objects.

The filter should be composed by users using logical OR / AND operators, and grouping using brackets.

say, something like this:

enter image description here

Say, we have object MyPerson and its properties Prop1, Prop2, etc...

Having myPersons list the user could filter elements: say Prop1 == aValue AND Prop2 < otherValue OR Prop2 > thirdvalue etc...

Now, I can build the chain of expression from the atoms (thanks to Jon Skeet from this question), like this:

Func<Person, bool> isAdult = person => person.Age > 18;
Func<Person, bool> isInParis = person => person.Location == "Paris";

var adultInParis = And(isAdult, isInParis);

My problem now is to transform the strings from the grid "Age", ">", "18" in the function expression "person.Age > 18", in order to link with an other one from the other row.

Community
  • 1
  • 1
serhio
  • 28,010
  • 62
  • 221
  • 374
  • 1
    http://stackoverflow.com/questions/821365/how-to-convert-a-string-to-its-equivalent-expression-tree – Vladimir Aug 12 '11 at 14:13
  • @Vladimir: However I don't understand how to use this DLL in my case. because this is not a person, but a collection of persons... there are expressions, here I need a function... – serhio Aug 12 '11 at 14:32
  • Wouldn't you just loop over the list of 'persons' and apply the filter? or building on the linked answer from Valdimir, `var filter = e.Compile(); var people = persons.Where(x => filter.DynamicInvoke(x) == true);` – CodingWithSpike Aug 12 '11 at 15:01
  • 1
    @rally25rs: The problem is not how to apply, but how to create. – serhio Aug 12 '11 at 15:38
  • But Vladimir's link has a couple options for how to create, including using the DLR. I guess I'm just not seeing enough code here to fully understand the hang-up... – CodingWithSpike Aug 12 '11 at 17:06

1 Answers1

0

Maybe you're looking for something like this:

class Program
{
    static void Main(string[] args)
    {
        Func<Person, bool> isInParis = BuildFunc("Location", "==", "Paris");
        Console.WriteLine(isInParis(new Person { Location = "Paris"})); // Prints true
        Console.WriteLine(isInParis(new Person { Location = "Venice"})); // Prints false
    }

    public class Person
    {
        public string Name { get; set; }
        public int Age { get; set; }
        public int Weight { get; set; }
        public DateTime FavouriteDay { get; set; }
        public string Location { get; set; }
    }

    private static Func<Person, bool> BuildFunc(
        string propertyName, 
        string comparisonOperator, 
        string propertyValue)
    {
        var parameter = Expression.Parameter(typeof (Person), "person");
        var property = Expression.Property(parameter, propertyName);
        var constant = Expression.Constant(propertyValue);

        Expression comparison;
        switch (comparisonOperator)
        {
            case "<":
                comparison = Expression.LessThan(property, constant);
                break;
            case ">":
                comparison = Expression.GreaterThan(property, constant);
                break;
            default:
                comparison = Expression.Equal(property, constant);
                break;
        }

        return Expression.Lambda<Func<Person, bool>>(comparison, parameter).Compile();
    }
}

Hope it helps!

andriys
  • 2,202
  • 2
  • 19
  • 24