如何在c#中构建不区分大小写的强类型LINQ查询?

时间:2011-10-13 12:21:17

标签: c# linq dynamic case-insensitive strong-typing

我尝试为IQuerable构建扩展方法,如下所示:

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

这将概括如下:

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

进入:

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

允许设置过滤运算符(即EndsWith,Contains)。

我在google上看到一些区分大小写的解决方案需要使用属性名称作为字符串而不是stron类型的propertySelectorExpression。我也看到了使用IndexOf()的不敏感的Contains()实现的解决方案,它们似乎不符合我的需求。

现在我有了这个,但它不起作用(在#34; ToLower()&#34;电话上激动):

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));
}

有什么想法吗?

1 个答案:

答案 0 :(得分:3)

这应该有效,即使当然不完整(也不优雅)。

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(如果Name为null,或者Test为null,或者Test.Name为null,或者GetValue()返回null)...