[英]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.