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

如何通过Expression.Call对IList<Item>用自定义函数实现筛选?

解决方案

要实现通过表达式树构建Items.Where(Foo)的等效逻辑,你需要构造对Enumerable.Where静态方法的调用表达式,而非仅针对单个Item调用Foo。以下是具体修改方案:

核心问题分析

原代码仅生成了单个Item调用Foo的表达式,未完成Where方法的整体调用逻辑。我们需要:

  1. 正确获取Enumerable.Where的泛型重载方法
  2. 构建筛选谓词(即Foo方法对应的委托/表达式)
  3. 组装完整的Where调用表达式

方案1:通过Lambda表达式构造谓词

此方式等价于Items.Where(item => Foo(item)),与Items.Where(Foo)效果一致:

using System.Linq.Expressions;
using System.Linq;

public static Expression BuildExpression(IList<Item> items)
{
    // 1. 定义Where方法的输入参数表达式(代表每个Item元素)
    var itemParam = Expression.Parameter(typeof(Item), "item");
    
    // 2. 构造调用Foo方法的表达式:Foo(item)
    // 替换YourClass为实际包含Foo方法的类名
    var fooCallExpr = Expression.Call(typeof(YourClass), "Foo", Type.EmptyTypes, itemParam);
    
    // 3. 构建筛选谓词的Lambda表达式:item => Foo(item)
    var predicateLambda = Expression.Lambda<Func<Item, bool>>(fooCallExpr, itemParam);
    
    // 4. 获取Enumerable.Where的泛型方法(适配IEnumerable<Item>和Func<Item,bool>的重载)
    var whereMethod = typeof(Enumerable).GetMethod(
        "Where", 
        new[] { typeof(IEnumerable<Item>), typeof(Func<Item, bool>) }
    );
    
    // 5. 构造完整的Where调用表达式:items.Where(predicateLambda)
    return Expression.Call(
        null, // 静态方法无需实例参数
        whereMethod,
        Expression.Constant(items),
        predicateLambda
    );
}

// 保持原Foo方法签名即可
private static bool Foo(Item item) 
{ 
    return item.Name.Equals("..."); 
}

方案2:直接传递Foo方法组(与Items.Where(Foo)完全一致)

如果希望严格匹配Items.Where(Foo)的写法(直接传递方法组),可以将Foo转换为Func<Item,bool>委托常量:

using System.Linq.Expressions;
using System.Linq;
using System.Reflection;

public static Expression BuildExpression(IList<Item> items)
{
    // 1. 获取Foo方法的MethodInfo(替换YourClass为实际类名)
    var fooMethod = typeof(YourClass).GetMethod(
        "Foo", 
        BindingFlags.Static | BindingFlags.NonPublic // 根据Foo的访问修饰符调整
    );
    
    // 2. 将Foo方法转换为Func<Item,bool>委托
    var fooDelegate = Delegate.CreateDelegate(typeof(Func<Item, bool>), fooMethod);
    
    // 3. 获取Enumerable.Where的泛型重载
    var whereMethod = typeof(Enumerable).GetMethods()
        .First(m => m.Name == "Where" && m.GetParameters().Length == 2)
        .MakeGenericMethod(typeof(Item));
    
    // 4. 构造Where调用表达式
    return Expression.Call(
        null,
        whereMethod,
        Expression.Constant(items),
        Expression.Constant(fooDelegate)
    );
}

关键注意事项

  • 替换代码中的YourClass为实际包含Foo方法的类名称
  • 如果Foo是实例方法,需调整Expression.Call的实例参数(传入实例的表达式),并修改GetMethod的绑定标志
  • 确保Foo方法的签名为bool Foo(Item item),否则需同步调整委托类型和表达式参数

内容的提问来源于stack exchange,提问作者styx

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 17:23:30