C#表达式树

表达式树(Expression Tree)是C#中表示Lambda表达式或代码的数据结构,允许在运行时分析、修改或执行代码。

动态条件构建

1 构建动态查询条件

using System.Collections.Generic;
using System.Reflection;

public class Person
{
    public int Id { get; set; }
    public string Name { get; set; }
    public int Age { get; set; }
    public string City { get; set; }
    public decimal Salary { get; set; }
    public DateTime BirthDate { get; set; }
}

public class DynamicConditionBuilder
{
    // 构建等于条件
    public static Expression<Func<T, bool>> BuildEqualExpression<T>(
        string propertyName, object value)
    {
        // 创建参数表达式
        ParameterExpression param = Expression.Parameter(typeof(T), "x");
        
        // 创建属性表达式
        MemberExpression property = Expression.Property(param, propertyName);
        
        // 如果属性类型与值类型不匹配,尝试转换
        if (value != null && property.Type != value.GetType())
        {
            value = Convert.ChangeType(value, property.Type);
        }
        
        // 创建常量表达式
        ConstantExpression constant = Expression.Constant(value);
        
        // 创建相等表达式
        BinaryExpression equalExpression = Expression.Equal(property, constant);
        
        // 创建Lambda表达式
        return Expression.Lambda<Func<T, bool>>(equalExpression, param);
    }
    
    // 构建范围条件
    public static Expression<Func<T, bool>> BuildRangeExpression<T>(
        string propertyName, object minValue, object maxValue)
    {
        ParameterExpression param = Expression.Parameter(typeof(T), "x");
        MemberExpression property = Expression.Property(param, propertyName);
        
        // 转换值类型
        if (minValue != null && property.Type != minValue.GetType())
            minValue = Convert.ChangeType(minValue, property.Type);
        
        if (maxValue != null && property.Type != maxValue.GetType())
            maxValue = Convert.ChangeType(maxValue, property.Type);
        
        ConstantExpression minConstant = Expression.Constant(minValue);
        ConstantExpression maxConstant = Expression.Constant(maxValue);
        
        // 大于等于最小值的条件
        BinaryExpression greaterThanOrEqual = Expression.GreaterThanOrEqual(
            property, minConstant);
        
        // 小于等于最大值的条件
        BinaryExpression lessThanOrEqual = Expression.LessThanOrEqual(
            property, maxConstant);
        
        // 组合两个条件(AND)
        BinaryExpression andExpression = Expression.AndAlso(
            greaterThanOrEqual, lessThanOrEqual);
        
        return Expression.Lambda<Func<T, bool>>(andExpression, param);
    }
    
    // 构建字符串包含条件
    public static Expression<Func<T, bool>> BuildContainsExpression<T>(
        string propertyName, string value)
    {
        ParameterExpression param = Expression.Parameter(typeof(T), "x");
        MemberExpression property = Expression.Property(param, propertyName);
        
        // 获取Contains方法
        MethodInfo containsMethod = typeof(string).GetMethod(
            "Contains", new[] { typeof(string) });
        
        ConstantExpression constant = Expression.Constant(value, typeof(string));
        
        // 创建方法调用表达式
        MethodCallExpression containsCall = Expression.Call(
            property, containsMethod, constant);
        
        return Expression.Lambda<Func<T, bool>>(containsCall, param);
    }
    
    public static void Demo()
    {
        // 使用示例
        var persons = new List<Person>
        {
            new Person { Id = 1, Name = "张三", Age = 25, City = "北京" },
            new Person { Id = 2, Name = "李四", Age = 30, City = "上海" },
            new Person { Id = 3, Name = "王五", Age = 35, City = "北京" }
        };
        
        // 构建动态条件
        Expression<Func<Person, bool>> ageCondition = 
            BuildRangeExpression<Person>("Age", 25, 30);
        
        Expression<Func<Person, bool>> cityCondition = 
            BuildEqualExpression<Person>("City", "北京");
        
        Expression<Func<Person, bool>> nameCondition = 
            BuildContainsExpression<Person>("Name", "");
        
        // 编译条件
        var ageFilter = ageCondition.Compile();
        var cityFilter = cityCondition.Compile();
        var nameFilter = nameCondition.Compile();
        
        // 应用过滤
        var ageResult = persons.Where(ageFilter);
        var cityResult = persons.Where(cityFilter);
        var nameResult = persons.Where(nameFilter);
        
        Console.WriteLine($"年龄在25-30之间: {ageResult.Count()}人");
        Console.WriteLine($"城市在北京: {cityResult.Count()}人");
        Console.WriteLine($"姓名包含'张': {nameResult.Count()}人");
    }
}

2 组合多个条件

public class ComplexConditionBuilder
{
    // 组合多个条件(AND)
    public static Expression<Func<T, bool>> And<T>(
        params Expression<Func<T, bool>>[] expressions)
    {
        if (expressions == null || expressions.Length == 0)
            return x => true;
            
        if (expressions.Length == 1)
            return expressions[0];
        
        // 从第一个表达式开始
        var result = expressions[0];
        
        for (int i = 1; i < expressions.Length; i++)
        {
            result = Combine(result, expressions[i], Expression.AndAlso);
        }
        
        return result;
    }
    
    // 组合多个条件(OR)
    public static Expression<Func<T, bool>> Or<T>(
        params Expression<Func<T, bool>>[] expressions)
    {
        if (expressions == null || expressions.Length == 0)
            return x => false;
            
        if (expressions.Length == 1)
            return expressions[0];
        
        var result = expressions[0];
        
        for (int i = 1; i < expressions.Length; i++)
        {
            result = Combine(result, expressions[i], Expression.OrElse);
        }
        
        return result;
    }
    
    // 组合两个表达式
    private static Expression<Func<T, bool>> Combine<T>(
        Expression<Func<T, bool>> expr1,
        Expression<Func<T, bool>> expr2,
        Func<Expression, Expression, BinaryExpression> combiner)
    {
        // 创建参数重映射器
        var parameter = Expression.Parameter(typeof(T));
        
        // 创建表达式访问器来重映射参数
        var leftVisitor = new ParameterReplaceVisitor(expr1.Parameters[0], parameter);
        var left = leftVisitor.Visit(expr1.Body);
        
        var rightVisitor = new ParameterReplaceVisitor(expr2.Parameters[0], parameter);
        var right = rightVisitor.Visit(expr2.Body);
        
        // 组合两个表达式
        var combined = combiner(left, right);
        
        return Expression.Lambda<Func<T, bool>>(combined, parameter);
    }
    
    // 参数替换访问器
    private class ParameterReplaceVisitor : ExpressionVisitor
    {
        private readonly ParameterExpression _oldParameter;
        private readonly ParameterExpression _newParameter;
        
        public ParameterReplaceVisitor(
            ParameterExpression oldParameter, 
            ParameterExpression newParameter)
        {
            _oldParameter = oldParameter;
            _newParameter = newParameter;
        }
        
        protected override Expression VisitParameter(ParameterExpression node)
        {
            return node == _oldParameter ? _newParameter : node;
        }
    }
    
    public static void Demo()
    {
        // 创建多个条件
        Expression<Func<Person, bool>> ageCondition = 
            p => p.Age >= 25 && p.Age <= 35;
            
        Expression<Func<Person, bool>> cityCondition = 
            p => p.City == "北京";
            
        Expression<Func<Person, bool>> salaryCondition = 
            p => p.Salary > 5000;
        
        // 组合条件:年龄25-35 AND (城市是北京 OR 工资大于5000)
        var complexCondition = And(
            ageCondition,
            Or(cityCondition, salaryCondition)
        );
        
        Console.WriteLine($"复杂条件: {complexCondition}");
    }
}

3 动态排序实现

public class DynamicOrderByBuilder
{
    // 动态构建排序表达式
    public static IQueryable<T> ApplyOrderBy<T>(
        IQueryable<T> query,
        string propertyName,
        bool descending = false)
    {
        // 验证属性是否存在
        var propertyInfo = typeof(T).GetProperty(propertyName);
        if (propertyInfo == null)
            throw new ArgumentException($"属性 '{propertyName}' 在类型 '{typeof(T).Name}' 中不存在");
        
        // 创建参数表达式
        ParameterExpression param = Expression.Parameter(typeof(T), "x");
        
        // 创建属性表达式
        MemberExpression property = Expression.Property(param, propertyInfo);
        
        // 创建Lambda表达式
        LambdaExpression lambda = Expression.Lambda(property, param);
        
        // 获取排序方法名
        string methodName = descending ? "OrderByDescending" : "OrderBy";
        
        // 反射调用OrderBy方法
        var method = typeof(Queryable).GetMethods()
            .First(m => m.Name == methodName && m.GetParameters().Length == 2)
            .MakeGenericMethod(typeof(T), propertyInfo.PropertyType);
        
        return (IQueryable<T>)method.Invoke(null, new object[] { query, lambda });
    }
    
    // 多列动态排序
    public static IQueryable<T> ApplyOrderBy<T>(
        IQueryable<T> query,
        params (string propertyName, bool descending)[] sortings)
    {
        var result = query;
        
        foreach (var sorting in sortings)
        {
            result = ApplyOrderBy(result, sorting.propertyName, sorting.descending);
        }
        
        return result;
    }
}

// 使用扩展方法形式
public static class QueryableExtensions
{
    public static IQueryable<T> OrderByDynamic<T>(
        this IQueryable<T> query,
        string propertyName,
        bool descending = false)
    {
        return DynamicOrderByBuilder.ApplyOrderBy(query, propertyName, descending);
    }
}

4 动态选择(Select)表达式

public class DynamicSelectBuilder
{
    // 创建匿名类型投影
    public static Expression<Func<T, object>> BuildSelectExpression<T>(
        params string[] propertyNames)
    {
        // 创建参数表达式
        ParameterExpression param = Expression.Parameter(typeof(T), "x");
        
        // 创建属性表达式列表
        List<MemberBinding> bindings = new List<MemberBinding>();
        List<Type> propertyTypes = new List<Type>();
        
        foreach (var propName in propertyNames)
        {
            var propertyInfo = typeof(T).GetProperty(propName);
            if (propertyInfo == null)
                continue;
                
            // 创建属性访问表达式
            MemberExpression propertyExpr = Expression.Property(param, propertyInfo);
            
            // 创建成员绑定
            bindings.Add(Expression.Bind(propertyInfo, propertyExpr));
            propertyTypes.Add(propertyInfo.PropertyType);
        }
        
        // 如果没有有效属性,返回null
        if (bindings.Count == 0)
            return null;
        
        // 创建匿名类型
        var anonymousType = CreateAnonymousType(propertyNames, propertyTypes);
        
        // 创建匿名类型构造函数
        NewExpression newExpr = Expression.New(anonymousType);
        
        // 创建成员初始化表达式
        MemberInitExpression initExpr = Expression.MemberInit(newExpr, bindings);
        
        // 创建Lambda表达式
        return Expression.Lambda<Func<T, object>>(
            Expression.Convert(initExpr, typeof(object)), param);
    }
    
    private static Type CreateAnonymousType(
        string[] propertyNames,
        Type[] propertyTypes)
    {
        // 使用反射创建匿名类型
        var assemblyName = new AssemblyName("DynamicTypes");
        var assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(
            assemblyName, AssemblyBuilderAccess.Run);
        var moduleBuilder = assemblyBuilder.DefineDynamicModule("MainModule");
        
        var typeBuilder = moduleBuilder.DefineType(
            "AnonymousType",
            TypeAttributes.Public | TypeAttributes.Class |
            TypeAttributes.Sealed | TypeAttributes.BeforeFieldInit);
        
        // 添加属性
        FieldInfo[] fields = new FieldInfo[propertyNames.Length];
        PropertyInfo[] properties = new PropertyInfo[propertyNames.Length];
        
        for (int i = 0; i < propertyNames.Length; i++)
        {
            // 添加字段
            fields[i] = typeBuilder.DefineField(
                $"_{propertyNames[i]}",
                propertyTypes[i],
                FieldAttributes.Private);
            
            // 添加属性
            properties[i] = typeBuilder.DefineProperty(
                propertyNames[i],
                PropertyAttributes.HasDefault,
                propertyTypes[i],
                null);
            
            // 定义get方法
            MethodBuilder getMethod = typeBuilder.DefineMethod(
                $"get_{propertyNames[i]}",
                MethodAttributes.Public | MethodAttributes.SpecialName |
                MethodAttributes.HideBySig,
                propertyTypes[i],
                Type.EmptyTypes);
            
            ILGenerator getIL = getMethod.GetILGenerator();
            getIL.Emit(OpCodes.Ldarg_0);
            getIL.Emit(OpCodes.Ldfld, fields[i]);
            getIL.Emit(OpCodes.Ret);
            
            // 定义set方法
            MethodBuilder setMethod = typeBuilder.DefineMethod(
                $"set_{propertyNames[i]}",
                MethodAttributes.Public | MethodAttributes.SpecialName |
                MethodAttributes.HideBySig,
                null,
                new Type[] { propertyTypes[i] });
            
            ILGenerator setIL = setMethod.GetILGenerator();
            setIL.Emit(OpCodes.Ldarg_0);
            setIL.Emit(OpCodes.Ldarg_1);
            setIL.Emit(OpCodes.Stfld, fields[i]);
            setIL.Emit(OpCodes.Ret);
            
            // 将方法与属性关联
            properties[i].SetGetMethod(getMethod);
            properties[i].SetSetMethod(setMethod);
        }
        
        // 定义构造函数
        ConstructorBuilder ctorBuilder = typeBuilder.DefineConstructor(
            MethodAttributes.Public,
            CallingConventions.Standard,
            propertyTypes);
        
        ILGenerator ctorIL = ctorBuilder.GetILGenerator();
        
        // 调用基类构造函数
        ctorIL.Emit(OpCodes.Ldarg_0);
        ctorIL.Emit(OpCodes.Call, typeof(object).GetConstructor(Type.EmptyTypes));
        
        // 初始化字段
        for (int i = 0; i < propertyTypes.Length; i++)
        {
            ctorIL.Emit(OpCodes.Ldarg_0);
            ctorIL.Emit(OpCodes.Ldarg_S, i + 1);
            ctorIL.Emit(OpCodes.Stfld, fields[i]);
        }
        
        ctorIL.Emit(OpCodes.Ret);
        
        return typeBuilder.CreateType();
    }
    
    public static void Demo()
    {
        var persons = new List<Person>
        {
            new Person { Id = 1, Name = "张三", Age = 25 },
            new Person { Id = 2, Name = "李四", Age = 30 }
        };
        
        // 动态选择Id和Name属性
        Expression<Func<Person, object>> selectExpr = 
            BuildSelectExpression<Person>("Id", "Name");
        
        if (selectExpr != null)
        {
            var func = selectExpr.Compile();
            var results = persons.Select(func);
            
            foreach (var result in results)
            {
                Console.WriteLine($"结果: {result}");
            }
        }
    }
}

 

posted @ 2025-12-20 09:43  CelonY  阅读(2)  评论(0)    收藏  举报