Halcyon
Halcyon

Reputation: 14971

Using Dynamic Linq To Filter A Collection

I want to use dynamic linq to match properties on an object. In my example, I have a Turtle class that has two properties. In the future, I may give it more properties. I have a FilterTurtles() method which is bound to the Turtle class's properties and isn't extensible. I'd like to use dynamic linq to make it extensible. For example, let's say I want to filter by the Name "Gilly" and the Color "Brown" and maybe a future property called "Breed". How can I filter the turtle collection using dynamic linq in the FilterTurtlesWithLinq() method?

public class Turtle
{
    public string Name { get; set; }
    public string Color { get; set; }
}

public class Filter
{
    public string Name { get; set ;}
    public string Value { get; set ;}
}   

public class Test
{
    private List<Turtle> Turtles { get; set;}

    public Test()
    {
        Turtles = new List<Turtle>();
        Turtles.Add(
        {
            new Turtle { Name = "Gilly", Color = "Brown" },
            new Turtle { Name = "Flow", Color = "Green" },
            new Turtle { Name = "Howard", Color = "Yellow" },
            new Turtle { Name = "Mara", Color = "Black" },
            new Turtle { Name = "Slimer", Color = "Green" },
            new Turtle { Name = "Tor", Color = "Brown" },
            new Turtle { Name = "Quartz", Color = "Yellow" },
            new Turtle { Name = "Gilly", Color = "Green" },
            new Turtle { Name = "Flow", Color = "Green" },
            new Turtle { Name = "Howard", Color = "Brown" }
        })
    }

    public IEnumerable<Turtle> FilterTurtles(string name, string color)
    {
        // This is the current code, but it's not extensible. If I add more properties
        // to the Turtle class, then I have to add more conditional statements.
        if (name != null)
        {
            return from t in Turtles
                   where t.Name == name
                   select t;
        }
        else if (color != null)
        {
            return from t in Turtles
                   where t.Color == color
                   select t;
        }
        else
        {
            return Turtles;
        }
    }

    public IEnumerable<Turtle> FilterTurtlesWithLinq(List<Filter> filters)
    {
        // I want to use dynamic linq here. For example, I want something like this:
        // "select all the turtles which match the filters"

        return null;
    }       
}

Upvotes: 2

Views: 140

Answers (1)

DavidG
DavidG

Reputation: 118937

You don't need to use dynamic Linq, how about a generic extension method that lets you pass in any number of filters, something like this:

public static IEnumerable<T> Filter<T>(this IEnumerable<T> input, 
    params Func<T, bool>[] filters)
{
    var filtered = input;

    foreach(var filter in filters)
    {
        filtered = filtered.Where(filter);
    }
    return filtered;
}

And you can use it like this:

var filteredTurtles = Turtles.Filter(
    t => t.Name == "Gilly", 
    t => t.Color == "Brown");

Upvotes: 5

Related Questions