【问题标题】:Apply inner expression filter on IQueryable在 IQueryable 上应用内部表达式过滤器
【发布时间】:2021-01-15 22:24:36
【问题描述】:

假设我有以下对象:

public class Source { public string Name; }
public class Target { public string Name; }
public class Result 
{ 
   public Source SourceObj; 
   public Target TargetObj; 
} 

现在,从某个地方获取IQueryable<Result>,我想为它准备表达式过滤器,只需将目标过滤器作为表达式:Expression<Func<Target, bool>> filter。过滤器方法签名如下所示:

public Expression<Func<Result, bool>> Filter(IQueryable<Result> collection, Expression<Func<Target, bool>> targetFilter)
{ 
   in result expression: "in given collection select items where their property TargetObj satisfies targetFilter"
}

任何建议将不胜感激。谢谢

【问题讨论】:

  • 这里有什么问题?

标签: c# linq lambda expression iqueryable


【解决方案1】:

我不确定我是否正确理解了您的目标,但我认为这可能是您想要的。

使用 linq Select,您可以映射源集合中的元素。所以在这里我们将结果映射到目标,然后应用您的目标过滤器。

public IQueryable<Target> GetFilteredTargets(IQueryable<Result> collection, Expression<Func<Target, bool>> targetFilter)
{
    return collection.Select(result => result.Target).Where(targetFilter);
}

【讨论】:

    【解决方案2】:

    如果你真的想要一个表达式作为 Filter 方法的返回值,你不需要 IQueryable&lt;Result&gt; collection

    public Expression<Func<Result, bool>> Filter(Expression<Func<Target, bool>> targetFilter)
    {
        Func<Target, bool> func = targetFilter.Compile();
        Expression<Func<Result, bool>> resultExpression = r => func(r.TargetObj);
    
        return resultExpression;
    }
    

    用法:

    var results = new List<Result>()
    {
       new Result() { TargetObj = new Target() { Name = "A" }},
       new Result() { TargetObj = new Target() { Name = "B" }},
       new Result() { TargetObj = new Target() { Name = "C" }},
    };
    
    var expression = Filter(r => r.Name == "B");
    var func = expression.Compile();
    
    var filteredResults = results.Where(r => func(r));
    

    这里的示例过滤结果将返回带有 B 的目标。根据我对您的目标的理解,直接使用 Linq Where 对我来说更有意义。

    编辑:由于您在问题中添加了一个新因素,因此您可以如何将目标过滤器添加到基本过滤器。

    public Expression<Func<Result, bool>> Filter(Expression<Func<Result, bool>> baseFilter, Expression<Func<Target, bool>> targetFilter)
    {
        Func<Result, bool> baseFunc = baseFilter.Compile();
        Func<Target, bool> targetFunc = targetFilter.Compile();
        Expression<Func<Result, bool>> resultExpression = r => baseFunc(r) && targetFunc(r.TargetObj);
    
        return resultExpression;
    }
    

    【讨论】:

    • 为了更清楚,我只是想稍微纠正一下我的问题。假设,我正在构建一个复杂的过滤器表达式来查询结果。而不是IQueryable&lt;Result&gt; collection,我的Filter 方法应该有baseFilter 参数并且看起来像public Expression&lt;Func&lt;Result, bool&gt;&gt; Filter(Expression&lt;Func&lt;Result, bool&gt;&gt; baseFilter, Expression&lt;Func&lt;Target, bool&gt;&gt; targetFilter)。此方法的目的是以某种方式“组合”这两个过滤器,使 targetFilter 成为 baseFilter 的“内部”过滤器之一。谢谢
    • @TimurGinesin 我更新了我的答案,以展示如何组合您的基本和目标过滤器表达式。
    猜你喜欢
    • 1970-01-01
    • 2021-01-04
    • 1970-01-01
    • 2020-06-24
    • 1970-01-01
    • 2020-11-12
    • 1970-01-01
    • 1970-01-01
    • 2019-12-22
    相关资源
    最近更新 更多