如何使用表达式树实现List的All方法?
用表达式树实现List.All的逻辑
没问题,我来一步步帮你实现这个表达式树版本的List.All逻辑,刚好能帮你解决当前的卡点~
先回顾下你要转换的原始代码:
var list = new List<CustomClass>(){ new CustomClass(){Id=10}}; var result = list.All(a => a.Id == 10);
首先咱们得明确,表达式树的核心是把代码逻辑拆成一个个可组合的表达式节点,然后拼接成完整的调用逻辑。下面是具体实现步骤:
1. 先定义基础类(如果还没定义的话)
public class CustomClass { public int Id { get; set; } }
2. 构建Lambda条件表达式(也就是a => a.Id == 10部分)
这部分是All方法需要的谓词参数:
// 定义lambda的输入参数:a ParameterExpression param = Expression.Parameter(typeof(CustomClass), "a"); // 获取CustomClass的Id属性表达式:a.Id MemberExpression idProperty = Expression.Property(param, nameof(CustomClass.Id)); // 定义常量10的表达式 ConstantExpression tenConstant = Expression.Constant(10, typeof(int)); // 构建等于判断表达式:a.Id == 10 BinaryExpression equalsCondition = Expression.Equal(idProperty, tenConstant); // 把条件包装成完整的lambda表达式 Expression<Func<CustomClass, bool>> predicateLambda = Expression.Lambda<Func<CustomClass, bool>>(equalsCondition, param);
3. 获取Enumerable.All的方法信息
因为All是Enumerable类下的静态泛型方法,咱们需要先拿到它的MethodInfo:
MethodInfo allMethod = typeof(Enumerable) .GetMethods(BindingFlags.Public | BindingFlags.Static) // 找到名为All且有2个参数的方法(第一个是集合,第二个是谓词) .First(m => m.Name == "All" && m.GetParameters().Length == 2) // 指定泛型类型为CustomClass .MakeGenericMethod(typeof(CustomClass));
4. 构建调用All方法的完整表达式
这里分两种情况:如果你的list是固定常量,或者是需要动态传入的变量:
情况1:list是常量实例
// 创建list实例 var listInstance = new List<CustomClass> { new CustomClass { Id = 10 } }; // 把list包装成常量表达式 ConstantExpression listConstant = Expression.Constant(listInstance, typeof(List<CustomClass>)); // 构建调用All的表达式:list.All(predicateLambda) MethodCallExpression allCall = Expression.Call( null, // 静态方法,第一个参数为null allMethod, listConstant, predicateLambda );
情况2:list是动态变量(更适合复杂场景复用)
如果你的list是局部变量或者需要动态传入,用ParameterExpression来定义:
// 定义list的参数表达式 ParameterExpression listParam = Expression.Parameter(typeof(List<CustomClass>), "list"); // 构建调用表达式 MethodCallExpression allCallWithVariable = Expression.Call( null, allMethod, listParam, predicateLambda );
5. 编译并执行表达式
最后把表达式编译成委托执行,就能得到和原始代码一样的结果:
对应情况1的执行
Func<bool> executeAll = Expression.Lambda<Func<bool>>(allCall).Compile(); bool result = executeAll(); // 结果为true
对应情况2的执行
Func<List<CustomClass>, bool> executeAllWithVariable = Expression.Lambda<Func<List<CustomClass>, bool>>(allCallWithVariable, listParam).Compile(); bool result2 = executeAllWithVariable(listInstance); // 结果为true
扩展说明
这个逻辑可以直接扩展到更复杂的场景:比如你需要动态生成不同的判断条件(比如a.Id > 5或者a.Name.Contains("test")),只需要修改中间的条件表达式部分就行;如果是其他集合类型,只需要调整MakeGenericMethod的类型参数即可。
内容的提问来源于stack exchange,提问作者user7784348
相关产品推荐
相关产品推荐

