views:

293

answers:

1

Update

Thanks to Marc's help the AlphaPagedList class is now available on CodePlex if anyone is interested

Original

I'm trying to create an expression tree to return elements that start with a given charecter.

IList<char> chars = new List<char>{'a','b'};
IQueryable<Dept>Depts.Where(x=> chars.Contains(x.DeptName[0]));

I want this to be used on any IEnumerable where I provide a lamdba to the property to select on eg:

Depts.Alpha(x=>x.DeptName, chars);

I've been trying this but having no luck at all, any help?

public static IQueryable<T> testing<T>(this IQueryable<T> queryableData, Expression<Func<T,string>> pi, IEnumerable<char> chars)
{
// Compose the expression tree that represents the parameter to the predicate.

ParameterExpression pe = Expression.Parameter(queryableData.ElementType, "x");
ConstantExpression ch = Expression.Constant(chars,typeof(IEnumerable<char>));
// ***** Where(x=>chars.Contains(x.pi[0])) *****
// pi is a string property
//Get the string property

Expression first = Expression.Constant(0);
//Get the first character of the string
Expression firstchar = Expression.ArrayIndex(pi.Body, first);
//Call "Contains" on chars with argument being right
Expression e = Expression.Call(ch, typeof(IEnumerable<char>).GetMethod("Contains", new Type[] { typeof(char) }),firstchar);


MethodCallExpression whereCallExpression = Expression.Call(
    typeof(Queryable),
    "Where",
    new Type[] { queryableData.ElementType },
    queryableData.Expression,
    Expression.Lambda<Func<T, bool>>(e, new ParameterExpression[] { pe }));
// ***** End Where *****

return (queryableData.Provider.CreateQuery<T>(whereCallExpression));
}
A: 

Something like (EDITED after re-reading the question) - but note that Expression.Invoke doesn't work on EF in 3.5SP1 (but it is fine in LINQ-to-SQL):

using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;

class Dept
{
    public string DeptName { get; set; }
}
public static class Program
{
    static void Main()
    {
        IList<char> chars = new List<char>{'a','b'};
        Dept[] depts = new[] { new Dept { DeptName = "alpha" }, new Dept { DeptName = "beta" }, new Dept { DeptName = "omega" } };
        var count = testing(depts.AsQueryable(), dept => dept.DeptName, chars).Count();
    }

    public static IQueryable<T> testing<T>(this IQueryable<T> queryableData, Expression<Func<T,string>> pi, IEnumerable<char> chars)
    {
        var arg = Expression.Parameter(typeof(T), "x");
        var prop = Expression.Invoke(pi, arg);
        Expression body = null;
        foreach(char c in chars) {
            Expression thisFilter = Expression.Call(prop, "StartsWith", null, Expression.Constant(c.ToString()));
            body = body == null ? thisFilter : Expression.OrElse(body, thisFilter);
        }
        var lambda = Expression.Lambda<Func<T, bool>>(body ?? Expression.Constant(false), arg);
        return queryableData.Where(lambda);
    }
}
Marc Gravell
Perfect, thanks so much for this. I'm working on an alpha-numeric paged list (along the lines of IPagedList) and this will be invaluable.
Chao