如何在LINQ查询中使用indexOf()实现不区分大小写的数据检索?
问题描述
我正在开发一个.NET C#项目,用于展示学生数据报表,需实现多字段的动态运行时搜索功能。当前使用Student、Class、State、City作为实体模型类,Filter类用于存储多列搜索值。
现有核心代码如下:
public class Student{ public string id{get;set;} public string first_name{get;set;} public string last_name{get;set;} public string address{get;set;} public string @class{get;set;} // 其他属性 } public class StudentModel{ public string Student_Id{get;set;} public string name{get;set;} public string @class{get;set;} public string class_teacher{get;set;} public string city{get;set;} public string country{get;set;} } var student_list=(from r in Student where (r.is_deleted == 0) select r).ToList(); var class_list=(from r in Class where (r.is_deleted == 0) select r).ToList(); var city_list=(from r in City where (r.is_deleted == 0) select r).ToList(); var state_list=(from r in State where (r.is_deleted == 0) select r).ToList(); List<Filter> filterList = new List<Filter>(); filterList.Add(new Filter("StudentId","Xc")); filterList.Add(new Filter("name","ab")); var deleg = ExpressionBuilder.GetExpression<StudentModel>(filterList).Compile(); list = (from stu in student_list join cls in class_list on stu.id equals cls.student_id join cty in city_list on stu.id equals cty.student_id into cityGrp from cty in cityGrp.DefaultIfEmpty() join st in state_list on stu.id equals st.student_id into stateGrp from st in stateGrp.DefaultIfEmpty() select new StudentModel { Student_Id = stu.id, name=stu.first_name, @class=cls.@class, class_teacher = cls.class_teacher, city=cty?.city, country=st?.country }).Where(deleg).ToList(); public class Filter { [JsonProperty("name")] public string name { get; set; } [JsonProperty("searchValue")] public string searchValue { get; set; } public Filter(string name,string searchValue){ this.name=name; this.searchValue=searchValue; } }
为了实现不区分大小写的动态搜索,我尝试用IndexOf替代区分大小写的Contains,编写了ExpressionBuilder类:
public class ExpressionBuilder { private static MethodInfo indexOfMethod = typeof(string).GetMethod("IndexOf", new Type[] { typeof(string) }); public static Expression<Func<T,bool>> GetExpression<T>(IList<Filter> filters) { if (filters.Count == 0) return null; ParameterExpression param = Expression.Parameter(typeof(T), "t"); Expression exp = null; if (filters.Count == 1) exp = GetExpression<T>(param, filters[0]); else if (filters.Count == 2) exp = GetExpression<T>(param, filters[0], filters[1]); else { while (filters.Count > 0) { var f1 = filters[0]; var f2 = filters[1]; if (exp == null) exp = GetExpression<T>(param, filters[0], filters[1]); else exp = Expression.AndAlso(exp, GetExpression<T>(param, filters[0], filters[1])); filters.Remove(f1); filters.Remove(f2); if (filters.Count == 1) { exp = Expression.AndAlso(exp, GetExpression<T>(param, filters[0])); filters.RemoveAt(0); } } } return Expression.Lambda<Func<T, bool>>(exp, param); } private static Expression GetExpression<T>(ParameterExpression param, Filter filter) { MemberExpression member = Expression.Property(param, filter.name); ConstantExpression constant = Expression.Constant(filter.searchValue); return Expression.Call(member, indexOfMethod, constant); } private static BinaryExpression GetExpression<T> (ParameterExpression param, Filter filter1, Filter filter2) { Expression bin1 = GetExpression<T>(param, filter1); Expression bin2 = GetExpression<T>(param, filter2); return Expression.AndAlso(bin1, bin2); } }
但运行时出现错误:Expression of type 'System.Int32' cannot be used for return type 'System.Boolean'
错误原因
string.IndexOf(string)方法返回int类型(匹配位置,未找到返回-1),但Linq的Where方法需要bool类型的表达式。当前代码直接返回IndexOf的调用结果,导致表达式类型不匹配,触发错误。同时,当前使用的IndexOf重载默认区分大小写,没有达到预期的不区分大小写搜索效果。
解决代码
1. 修正ExpressionBuilder核心逻辑
修改单个Filter的表达式构建逻辑,将IndexOf的结果与0比较(>=0表示找到匹配),同时改用带StringComparison参数的IndexOf重载实现不区分大小写,并添加空值检查避免异常:
public class ExpressionBuilder { // 改用带StringComparison参数的IndexOf重载 private static MethodInfo indexOfMethod = typeof(string).GetMethod( "IndexOf", new Type[] { typeof(string), typeof(StringComparison) }); public static Expression<Func<T, bool>> GetExpression<T>(IList<Filter> filters) { if (filters.Count == 0) return null; ParameterExpression param = Expression.Parameter(typeof(T), "t"); Expression exp = null; // 优化多filter处理逻辑,避免修改原集合 var remainingFilters = new List<Filter>(filters); while (remainingFilters.Count > 0) { var currentFilter = remainingFilters[0]; var currentExpr = GetSingleFilterExpression<T>(param, currentFilter); exp = exp == null ? currentExpr : Expression.AndAlso(exp, currentExpr); remainingFilters.RemoveAt(0); } return Expression.Lambda<Func<T, bool>>(exp, param); } // 单独处理单个Filter的表达式 private static Expression GetSingleFilterExpression<T>(ParameterExpression param, Filter filter) { MemberExpression member = Expression.Property(param, filter.name); // 处理属性为null的情况,避免NullReferenceException var nullCheck = Expression.NotEqual(member, Expression.Constant(null)); // 构建IndexOf调用:member.IndexOf(searchValue, StringComparison.OrdinalIgnoreCase) var indexOfCall = Expression.Call( member, indexOfMethod, Expression.Constant(filter.searchValue), Expression.Constant(StringComparison.OrdinalIgnoreCase)); // 构建条件:indexOfResult >= 0 var matchCheck = Expression.GreaterThanOrEqual(indexOfCall, Expression.Constant(0)); // 合并null检查和匹配检查:属性不为null 且 找到匹配 return Expression.AndAlso(nullCheck, matchCheck); } }
2. 其他代码修正
- Filter类的构造函数需改为
public,否则无法在外部实例化 - Linq查询中修正join关联字段错误,并添加空值处理避免空引用
关键优化点
- 解决类型不匹配问题:将IndexOf的int结果转换为bool表达式(>=0)
- 实现真正的不区分大小写搜索:使用
StringComparison.OrdinalIgnoreCase参数 - 添加null检查:避免属性为null时调用IndexOf抛出异常
- 优化多filter处理逻辑:不再修改原filter集合,避免副作用
内容的提问来源于stack exchange,提问作者santosh
相关产品推荐
相关产品推荐

