How to build a case insensitive strong typed LINQ query in C #?

I am trying to build an extension method for IQuerable as follows:

public static IQueryable<T> FilterByString<T>(this IQueryable<T> query, 
  Expression<Func<T, string>> propertySelector, 
  StringOperator operand, 
  string value)

which will generalize something like this:

query.Where(o => o.Name.ToLower().StartsWith(filterObject.Name.ToLower()))

at:

q.FilterByString(o => o.Name, filterObject.NameOperator, filterObject.Name)

to allow the installation of a filter operator (i.e. EndsWith, Contains).

I saw on Google some solutions for case-sensitive filtering, which requires the use of a property name as a string instead of a string typed PropertySelectorExpression. I also saw a solution for the insensitive implementation of Contains () using IndexOf (), but it doesn't seem like they fit my needs.

At the moment I have this, but it does not work (excpetiopn on a call to ToLower ()):

static MethodInfo miTL = typeof(String).GetMethod("ToLower", System.Type.EmptyTypes);
static MethodInfo miS = typeof(String).GetMethod("StartsWith", new Type[] { typeof(String) });
static MethodInfo miC = typeof(String).GetMethod("Contains", new Type[] { typeof(String) });
static MethodInfo miE = typeof(String).GetMethod("EndsWith", new Type[] { typeof(String) });

public static IQueryable<T> FilterByString<T>(this IQueryable<T> query, 
  Expression<Func<T, string>> propertySelector, 
  StringOperator operand, 
  string value)
{
    Expression constExp = Expression.Constant(value.ToLower());

    Expression dynamicExpression = null;

    switch (operand)
    {
        case StringOperator.StartsWith:
            dynamicExpression = Expression.Call(propertySelector, miTL);
            dynamicExpression = Expression.Call(dynamicExpression, miS, constExp);
            break;
        case StringOperator.Contains:
            dynamicExpression = Expression.Call(propertySelector, miTL);
            dynamicExpression = Expression.Call(dynamicExpression, miC, constExp);
            break;
        case StringOperator.EndsWith:
            dynamicExpression = Expression.Call(dynamicExpression, miTL);
            dynamicExpression = Expression.Call(dynamicExpression, miE, constExp);
            break;
        default:
            break;
    }

    LambdaExpression pred = Expression.Lambda(dynamicExpression);

    return (IQueryable<T>)query.Provider.CreateQuery(Expression.Call(typeof(Queryable), 
        "Where", new Type[] {query.ElementType}, query.Expression, pred));
}

Any ideas?

+5
1

, , , ( ).

public static class LinqQueries
{
    private static MethodInfo miTL = typeof(String).GetMethod("ToLower", Type.EmptyTypes);
    private static MethodInfo miS = typeof(String).GetMethod("StartsWith", new Type[] { typeof(String) });
    private static MethodInfo miC = typeof(String).GetMethod("Contains", new Type[] { typeof(String) });
    private static MethodInfo miE = typeof(String).GetMethod("EndsWith", new Type[] { typeof(String) });

    public static IQueryable<T> FilterByString<T>(this IQueryable<T> query,
                                                  Expression<Func<T, string>> propertySelector,
                                                  StringOperator operand,
                                                  string value)
    {
        ParameterExpression parameterExpression = null;
        var memberExpression = GetMemberExpression(propertySelector.Body, out parameterExpression);
        var dynamicExpression = Expression.Call(memberExpression, miTL);
        Expression constExp = Expression.Constant(value.ToLower());
        switch (operand)
        {
            case StringOperator.StartsWith:
                dynamicExpression = Expression.Call(dynamicExpression, miS, constExp);
                break;
            case StringOperator.Contains:
                dynamicExpression = Expression.Call(dynamicExpression, miC, constExp);
                break;
            case StringOperator.EndsWith:
                dynamicExpression = Expression.Call(dynamicExpression, miE, constExp);
                break;
        }

        var pred = Expression.Lambda<Func<T, bool>>(dynamicExpression, new[] { parameterExpression });
        return query.Where(pred);

    }


    private static Expression GetMemberExpression(Expression expression, out ParameterExpression parameterExpression)
    {
        parameterExpression = null;
        if (expression is MemberExpression)
        {
            var memberExpression = expression as MemberExpression;
            while (!(memberExpression.Expression is ParameterExpression))
                memberExpression = memberExpression.Expression as MemberExpression;
            parameterExpression = memberExpression.Expression as ParameterExpression;
            return expression as MemberExpression;
        }
        if (expression is MethodCallExpression)
        {
            var methodCallExpression = expression as MethodCallExpression;
            parameterExpression = methodCallExpression.Object as ParameterExpression;
            return methodCallExpression;
        }
        return null;
    }

}

xxx.FilterByString(m => m.Name,...)
xxx.FilterByString(m => m.Test.Name,...)
xxx.FilterByString(m => m.GetValue(),...)//GetValue() returns "string"

: NullReferenceExceptions ( null Test null Test.Name null, GetValue() null)...

+3

All Articles