C#表达式组合



假设我有两个类:

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包含检查

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

那么我该如何在我的中使用它。在哪里我可以重写ParentsChildNameMatches?

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

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

您可以使用表达式树API手动完成此操作,也可以使用一些第三方库,如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

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

您可以将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 => parent.Child,并将其用作childPredicate的参数

最新更新