假设我们有两个班级
public class EntityA
{
public EntityB EntityB { get; set; }
}
public class EntityB
{
public string Name { get; set; }
public bool IsDeleted { get; set; }
}
选择器和谓词的两个表达式
Expression<Func<EntityA, EntityB>> selector = c => c.EntityB;
Expression<Func<EntityB, bool>> predicate = c => c.IsDeleted && c.Name == "AAA";
我需要编写一个返回组合表达式的方法,如
Expression<Func<TSource, bool>> Compose<TPropType>(Expression<Func<TSource, TPropType>> selector, Expression<Func<TPropType, bool>> predicator)
{
// Expression API ???
}
在我的示例中,结果应为
Expression<Func<EntityA, bool>> exp = Compose(selector, predicate);
等同于
Expression<Func<EntityA, bool>> exp = c => c.EntityB.IsDeleted && c.EntityB.Name == "AAA";
提前致谢。
答案 0 :(得分:3)
调用这些lambda表达式肯定是你不想做的事情。你应该做的是重写表达式。您只需要一种方法将值绑定到lambda表达式,就像调用它们一样。为此,重写表达式的主体,用您要绑定的值替换参数。您可以使用此SubstitutionVisitor
来帮助完成此操作:
public class SubstitutionVisitor : ExpressionVisitor
{
public Expression OldExpr { get; set; }
public Expression NewExpr { get; set; }
public override Expression Visit(Expression node)
{
return (node == OldExpr) ? NewExpr : base.Visit(node);
}
}
给出这些表达式例如:
Expression<Func<EntityA, EntityB>> selector =
entityA => entityA.EntityB;
Expression<Func<EntityB, bool>> predicate =
entityB => entityB.IsDeleted && entityB.Name == "AAA";
目标是有效地重写它,使它变成这样:
Expression<Func<EntityA, bool>> composed =
entity => entity.EntityB.IsDeleted && entity.EntityB.Name == "AAA";
static Expression<Func<TSource, bool>> Compose<TSource, TProp>(
Expression<Func<TSource, TProp>> selector,
Expression<Func<TProp, bool>> predicate)
{
var parameter = Expression.Parameter(typeof(TSource), "entity");
var property = new SubstitutionVisitor
{
OldExpr = selector.Parameters.Single(),
NewExpr = parameter,
}.Visit(selector.Body);
var body = new SubstitutionVisitor
{
OldExpr = predicate.Parameters.Single(),
NewExpr = property,
}.Visit(predicate.Body);
return Expression.Lambda<Func<TSource, bool>>(body, parameter);
}
要了解这里发生了什么,这里有一个逐行解释:
为我们正在创建的新lambda创建一个新参数。
entity => ...
给定选择器,将原始参数entityA
的所有实例替换为lambda正文中的新参数entity
以获取属性。
entityA => entityA.EntityB
// becomes
entity.EntityB
给定谓词,用lambda主体中先前获得的属性entityB
替换原始参数entity.EntityB
的所有实例,以获得新lambda的主体。
entityB => entityB.IsDeleted && entityB.Name == "AAA"
// becomes
entity.EntityB.IsDeleted && entity.EntityB.Name == "AAA"
将所有内容放在新的lambda中。
entity => entity.EntityB.IsDeleted && entity.EntityB.Name == "AAA"
答案 1 :(得分:0)
您可以尝试以下操作:
static Expression<Func<TSource, bool>> Compose<TSource, TPropType>(
Expression<Func<TSource, TPropType>> selector,
Expression<Func<TPropType, bool>> predicator)
{
ParameterExpression param = Expression.Parameter(typeof(TSource), "sourceObj");
Expression invokedSelector = Expression.Invoke(selector, new Expression[] { param });
Expression invokedPredicate = Expression.Invoke(predicator, new[] { invokedSelector });
return Expression.Lambda<Func<TSource, bool>>(invokedPredicate, new[] { param });
}
以下是如何使用它:
static void Main()
{
Expression<Func<EntityA, EntityB>> selector = c => c.EntityB;
Expression<Func<EntityB, bool>> predicate = c => c.IsDeleted && c.Name == "AAA";
Expression<Func<EntityA, bool>> exp = Compose(selector, predicate);
System.Console.WriteLine(exp.Compile()(new EntityA()));
}