You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 10:37:03