score:10

Accepted answer

you can build a lambda expression to create a proper predicate using the expression class.

public static expression<func<tinput, bool>> createfilterexpression<tinput>(
                                                   ienumerable<filter> filters)
{
    parameterexpression param = expression.parameter(typeof(tinput), "");
    expression lambdabody = null;
    if (filters != null)
    {
        foreach (filter filter in filters)
        {
            expression compareexpression = expression.equal(
                    expression.property(param, filter.fieldname),
                    expression.constant(filter.filterstring));
            if (lambdabody == null)
                lambdabody = compareexpression;
            else
                lambdabody = expression.or(lambdabody, compareexpression);
        }
    }
    if (lambdabody == null)
        return expression.lambda<func<tinput, bool>>(expression.constant(false));
    else
        return expression.lambda<func<tinput, bool>>(lambdabody, param);
}

with this helper method, you can create an extension method on any iqueryable<t> class, so this should work for every linq backend:

public static iqueryable<t> where<t>(this iqueryable<t> source, 
                                          ienumerable<filter> filters)
{
    return queryable.where(source, createfilterexpression<t>(filters));
}

...which you can call like this:

var query = context.persons.where(userfilters);

if you want to support ienumerable<t> collections as well, you'll need to use this extra extension method:

public static ienumerable<t> where<t>(this ienumerable<t> source, 
                                           ienumerable<filter> filters)
{
    return enumerable.where(source, createfilterexpression<t>(filters).compile());
}

note that this only works for string properties. if you want to filter on fields, you'll need to change expression.property into expression.field (or makememberaccess), and if you need to support other types than string properties, you'll have to provide more type information to the expression.constant part of the createfilterexpression method.

score:0

i would add a method to the filter class to check if the filter is satisfied:

class filter 
{
    public string fieldname {get;set;}
    public string filterstring {get;set;}

    public bool issatisfied(object o)
    { return o.gettype().getproperty(fieldname).getvalue(o, null) as string == filterstring;
}

you can then use it like this:

var filtered_list = personslist.where(p => userfilters.any(f => f.issatisfied(p)));

score:2

can't you just do

personlist.where(x => x.personname == "yournamehere").tolist() ?

score:3

you can do it via reflection:

iqueryable<person> filteredpersons = personslist.asqueryable();
type persontype = typeof(person);
foreach(filter filter in userfilters) {
    filteredpersons = filteredpersons.where(p => (string)persontype.invokemember(filter.fieldname, bindingflags.getproperty, null, p, null) == filter.filterstring);
}

(not compiled, but this should be along the right track)


Related Query

More Query from same tag