当前位置: 首页 > news >正文

C#中表达式树实现动态拼接lamda表达式查询条件

在C#中,表达式树(Expression Trees)可以用于动态构建和拼接Lambda表达式,特别是在需要动态生成查询条件时非常有用。通过表达式树,你可以在运行时构建复杂的查询条件,而不需要在编译时硬编码这些条件。

下面是一个简单的示例,展示如何使用表达式树动态拼接Lambda表达式查询条件。

示例场景

假设我们有一个Person类,并且我们想要根据不同的条件动态查询Person对象。

csharp

public class Person
{
    public string Name { get; set; }
    public int Age { get; set; }
    public string City { get; set; }
}

动态拼接Lambda表达式

我们可以使用Expression类来动态构建查询条件。以下是一个示例,展示如何根据不同的条件动态拼接Lambda表达式。

csharp

using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;

public class Program
{
    public static void Main()
    {
        var people = new List<Person>
        {
            new Person { Name = "Alice", Age = 25, City = "New York" },
            new Person { Name = "Bob", Age = 30, City = "Los Angeles" },
            new Person { Name = "Charlie", Age = 35, City = "New York" },
            new Person { Name = "David", Age = 40, City = "Chicago" }
        };

        // 动态构建查询条件
        Expression<Func<Person, bool>> condition = BuildCondition("New York", 30);

        // 应用条件并过滤数据
        var filteredPeople = people.AsQueryable().Where(condition).ToList();

        foreach (var person in filteredPeople)
        {
            Console.WriteLine($"{person.Name}, {person.Age}, {person.City}");
        }
    }

    public static Expression<Func<Person, bool>> BuildCondition(string city, int minAge)
    {
        // 创建参数表达式
        var parameter = Expression.Parameter(typeof(Person), "p");

        // 创建属性表达式
        var cityProperty = Expression.Property(parameter, "City");
        var ageProperty = Expression.Property(parameter, "Age");

        // 创建常量表达式
        var cityValue = Expression.Constant(city);
        var minAgeValue = Expression.Constant(minAge);

        // 创建比较表达式
        var cityCondition = Expression.Equal(cityProperty, cityValue);
        var ageCondition = Expression.GreaterThanOrEqual(ageProperty, minAgeValue);

        // 组合条件
        var combinedCondition = Expression.AndAlso(cityCondition, ageCondition);

        // 创建Lambda表达式
        return Expression.Lambda<Func<Person, bool>>(combinedCondition, parameter);
    }
}

代码解释

  1. BuildCondition 方法:该方法动态构建了一个Expression<Func<Person, bool>>,表示一个Lambda表达式,用于过滤Person对象。

    • Expression.Parameter:创建一个参数表达式,表示Lambda表达式的输入参数。

    • Expression.Property:创建一个属性访问表达式,表示访问Person对象的属性。

    • Expression.Constant:创建一个常量表达式,表示常数值。

    • Expression.Equal 和 Expression.GreaterThanOrEqual:创建比较表达式,分别表示等于和大于等于的比较。

    • Expression.AndAlso:将两个条件表达式组合成一个逻辑与(AND)表达式。

    • Expression.Lambda:将组合后的表达式包装成一个Lambda表达式。

  2. 应用条件:在Main方法中,我们调用BuildCondition方法生成查询条件,并将其应用于people列表,过滤出符合条件的Person对象。

输出

运行上述代码后,输出将是符合条件的Person对象:

复制

Alice, 25, New York
Charlie, 35, New York

 

如果你的查询条件个数是不确定的,可以通过动态组合多个条件表达式来实现。你可以使用Expression.AndAlsoExpression.OrElse来将多个条件表达式动态拼接成一个完整的表达式树。

以下是一个示例,展示如何根据不确定的条件个数动态拼接Lambda表达式查询条件。


示例场景2

假设我们有一个Person类,并且我们想要根据用户提供的多个条件动态查询Person对象。每个条件可能是一个属性与值的比较(例如City == "New York"Age >= 30),我们需要将这些条件动态组合起来。


实现代码2

csharp

using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;

public class Person
{
    public string Name { get; set; }
    public int Age { get; set; }
    public string City { get; set; }
}

public class Program
{
    public static void Main()
    {
        var people = new List<Person>
        {
            new Person { Name = "Alice", Age = 25, City = "New York" },
            new Person { Name = "Bob", Age = 30, City = "Los Angeles" },
            new Person { Name = "Charlie", Age = 35, City = "New York" },
            new Person { Name = "David", Age = 40, City = "Chicago" }
        };

        // 动态构建查询条件
        var conditions = new List<Expression<Func<Person, bool>>>
        {
            p => p.City == "New York", // 条件1:City == "New York"
            p => p.Age >= 30           // 条件2:Age >= 30
        };

        // 动态拼接条件
        var combinedCondition = CombineConditions(conditions);

        // 应用条件并过滤数据
        var filteredPeople = people.AsQueryable().Where(combinedCondition).ToList();

        foreach (var person in filteredPeople)
        {
            Console.WriteLine($"{person.Name}, {person.Age}, {person.City}");
        }
    }

    /// <summary>
    /// 动态拼接多个条件表达式
    /// </summary>
    /// <param name="conditions">条件列表</param>
    /// <returns>拼接后的条件表达式</returns>
    public static Expression<Func<Person, bool>> CombineConditions(List<Expression<Func<Person, bool>>> conditions)
    {
        if (conditions == null || !conditions.Any())
        {
            return p => true; // 如果没有条件,返回一个恒真条件
        }

        // 获取第一个条件
        var combinedCondition = conditions[0];

        // 遍历剩余条件,逐个拼接
        for (int i = 1; i < conditions.Count; i++)
        {
            var nextCondition = conditions[i];

            // 使用 Expression.AndAlso 拼接条件
            var parameter = Expression.Parameter(typeof(Person), "p");
            var body = Expression.AndAlso(
                Expression.Invoke(combinedCondition, parameter),
                Expression.Invoke(nextCondition, parameter)
            );

            combinedCondition = Expression.Lambda<Func<Person, bool>>(body, parameter);
        }

        return combinedCondition;
    }
}

代码解释2

  1. CombineConditions 方法

    • 该方法接收一个List<Expression<Func<Person, bool>>>,表示多个条件表达式。

    • 如果没有条件,返回一个恒真条件(p => true)。

    • 使用Expression.AndAlso将多个条件动态拼接成一个完整的表达式树。

  2. 动态拼接条件

    • 使用Expression.Invoke调用每个条件表达式。

    • 使用Expression.AndAlso将多个条件组合成一个逻辑与(AND)表达式。

  3. 应用条件

    • Main方法中,我们定义了两个条件(City == "New York"Age >= 30),并将它们动态拼接成一个完整的查询条件。

    • 使用Where方法将拼接后的条件应用于people列表,过滤出符合条件的Person对象。


输出2

运行上述代码后,输出将是符合条件的Person对象:

复制

Charlie, 35, New York

支持更多条件

如果你需要支持更多的条件(例如OR逻辑或更复杂的组合),可以扩展CombineConditions方法。例如:

  • 使用Expression.OrElse实现逻辑或(OR)组合。

  • 支持动态选择逻辑运算符(AND 或 OR)。


扩展:支持动态逻辑运算符

以下是一个扩展版本,支持动态选择逻辑运算符(AND 或 OR):

csharp

public static Expression<Func<Person, bool>> CombineConditions(
    List<Expression<Func<Person, bool>>> conditions,
    Func<Expression, Expression, BinaryExpression> logicalOperator)
{
    if (conditions == null || !conditions.Any())
    {
        return p => true; // 如果没有条件,返回一个恒真条件
    }

    // 获取第一个条件
    var combinedCondition = conditions[0];

    // 遍历剩余条件,逐个拼接
    for (int i = 1; i < conditions.Count; i++)
    {
        var nextCondition = conditions[i];

        // 使用指定的逻辑运算符拼接条件
        var parameter = Expression.Parameter(typeof(Person), "p");
        var body = logicalOperator(
            Expression.Invoke(combinedCondition, parameter),
            Expression.Invoke(nextCondition, parameter)
        );

        combinedCondition = Expression.Lambda<Func<Person, bool>>(body, parameter);
    }

    return combinedCondition;
}

调用时可以选择逻辑运算符:

csharp

// 使用 AND 逻辑
var combinedCondition = CombineConditions(conditions, Expression.AndAlso);

// 使用 OR 逻辑
var combinedCondition = CombineConditions(conditions, Expression.OrElse);

总结

通过动态拼接表达式树,你可以灵活地处理不确定数量的查询条件,并根据需要组合逻辑运算符(AND 或 OR)。这种方法非常适合动态查询场景,例如根据用户输入生成复杂的查询条件。

相关文章:

  • STL之string类的模拟实现
  • Eclipse插件开发六:使用Web前端技术开发AI助手页面
  • JDK最详细安装教程,零基础入门到精通,收藏这篇就够了
  • 网络原理-
  • springboot pagehelper分页插件封装
  • 【Bert】自然语言(Language Model)入门之---Bert
  • 企业内部知识库:安全协作打造企业智慧运营基石
  • leetcode 2585. 获得分数的方法数
  • C/C++ 格式化输出( unsigned long long)
  • vue stores全局状态共享
  • alphafold3本地部署
  • 划分字母区间
  • 【Qt】常用控件(一)
  • 【练习】【二分】力扣热题100 153. 寻找旋转排序数组中的最小值
  • C++ Qt建立一个HTTP服务器
  • 鸿蒙开发:V2版本装饰器之@Monitor装饰器
  • 阐解WiFi信号强度
  • Linux centOS7 bash编程小技巧
  • Vue3中的setup
  • Linux应用之构建命令行解释器(bash进程)
  • 秦洪看盘|资金切换主线,重构市场风格
  • 如何反击右翼思潮、弥合社会分裂:加拿大大选镜鉴
  • 中国公民在日本被机动车碾压身亡,我使馆发布提醒
  • 马上评丨又见酒店坐地起价,“老毛病”不能惯着
  • 卸任兰大校长后,严纯华院士重返北大作报告
  • “85后”潘欢欢已任河南中豫融资担保有限公司总经理