【问题标题】:C# Expression composition [duplicate]C#表达式组合[重复]
【发布时间】:2018-07-17 15:08:42
【问题描述】:

假设我有两个班级:

public class Parent {
   public Child Child { get; set; }
}

public class Child {
   public string Name { get; set; }
}

我想编写一个函数,通过包含子字符串的孩子的名字过滤父母。

public IQueryable<Parent> ParentsChildNameMatches(IQueryable<Parent> parents, string word)
{
   return parents.Where(parent => parent.Child.Name.Contains(word));
}

如果我想取出那个表达式,以便我可以在其他地方重用 Child contains 检查

public Expression<Func<Child, bool> ChildNameMatches(string word)
{
   return child => child.Name.Contains(word));
}

然后如何在我的 .Where 中使用它以便我可以重写 ParentChildNameMatches?

public IQueryable<Parent> ParentsChildNameMatches(IQueryable<Parent> parents, string word)
{
   return parents.Where( // how to leverage ChildNameMatches?
}

【问题讨论】:

  • 其实,你的ChildNameMatches不应该接受Parent,而不是Child,而是return parent =&gt; parent.Child. ...吗?
  • 好吧,我的目标是,我可以自己重用 ChildNameMatches 表达式,用于 Child 类,或者当有其他具有 Child 属性的父类时。
  • 如果在Child 类中定义了特定方法ChildNameMatches,那么您可以添加另一个具有我为Parent 类建议的签名的方法,否则您将无法直接在 .Where() 调用中使用它。

标签: c# lambda expression iqueryable


【解决方案1】:

因此,给定一个Expression&lt;Func&lt;Child, bool&gt;&gt;,并且您可以通过Parent 类中的Child 属性创建从ParentChild 的表达式,您希望获得一个Expression&lt;Func&lt;Parent, bool&gt;&gt;

您可以使用 expression trees API 手动执行此操作,或者您可以使用一些 3rd 方库,例如 LinqKit,如下所示:

public IQueryable<Parent> ParentsChildNameMatches(IQueryable<Parent> parents, string word)
{
    var childExpression = ChildNameMatches(word);

    Expression<Func<Parent, bool>> expression = p => childExpression.Invoke(p.Child);

    expression = expression.Expand();

    return parents.Where(expression);
}

LinqKit 提供了Invoke 方法,允许您将表达式组合在一起。它还提供了Expand 方法,可以将结果表达式展平。

您可以在此处阅读更多相关信息:http://www.albahari.com/nutshell/linqkit.aspx

已更新:之前的代码不起作用。固定。

【讨论】:

  • 谢谢,更新后,这对我有用。出于好奇,您什么时候需要额外使用 linqkit.entityframework?
  • 我真的不知道。也许你可以在图书馆的项目网站上找到这样的信息。
【解决方案2】:

您可以将您的 lambda 表达式与 Invoke 结合使用

public static IQueryable<Parent> ParentsChildNameMatches(IQueryable<Parent> parents, string word)
{
    var childPredicate = ChildNameMatches(word);

    var parent = Expression.Parameter(typeof(Parent), "parent");
    var parentPredicate = Expression.Lambda<Func<Parent, bool>>(
        Expression.Invoke(
            childPredicate, 
            Expression.Property(parent, "Child")),
        parent);

    return parents.Where(parentPredicate);
}

此代码将创建一个新表达式parent =&gt; parent.Child 并将其用作childPredicate 的参数

【讨论】:

    猜你喜欢
    • 2012-11-11
    • 1970-01-01
    • 2018-08-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多