简体   繁体   English

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

[英]how to build case insensitive strong typed LINQ query in c#?

I try to build extension method for IQuerable like this: 我尝试为IQuerable构建扩展方法,如下所示:

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

that will generalize something like this: 这将概括如下:

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

into: 成:

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

to allow to set filtering operator (ie EndsWith, Contains). 允许设置过滤运算符(即EndsWith,Contains)。

I've seen on google some solutions to case sensitive filtering that requires using name of the property as a string instead of stron typed propertySelectorExpression. 我在google上看到了一些区分大小写的解决方案,需要使用属性的名称作为字符串而不是stron类型的propertySelectorExpression。 I've also seen solution for insensitive Contains() implementation using IndexOf() bu non of them seems to fit my needs. 我也看到使用IndexOf()的不敏感的Contains()实现的解决方案,它们似乎不符合我的需要。

For now I have this but it is not working (excpetiopn on "ToLower()" call): 现在我有这个,但它不起作用(在“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? 有任何想法吗?

This should work, even if certainly not complete (nor elegant). 这应该有效,即使当然不完整(也不优雅)。

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

}

Will manage 会管理

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

CAUTION : NullReferenceExceptions aren't managed (if Name is null, or Test is null, or Test.Name is null, or GetValue() returns null)... 注意:不管理NullReferenceExceptions(如果Name为null,或者Test为null,或者Test.Name为null,或者GetValue()返回null)...

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM