如何转换表达式树?

更新

我会试着解释一下我的意思。 有2个不同的类(MyClass1和MyClass2)以及将class1转换为class2的方法:

class MyClass1 { //...Some fields and properties } class MyClass2 { //...Some fields and properties } public MyClass2 Convert(MyClass1 class1) { //..... return class2Object; } 

有两种不同的方法:

  void method1(Expression<Func> where, //other parameters) { //some operations //............... //need to call method2(Expression<Func>) // BUT! How do I convert Expression<Func> // to Expression<Func> } void method2(Expression<Func> where, //other parameters) { //some operations } 

如何将Expression <Func < MyClass1 ,bool >>转换为Expression <Func < MyClass2 ,bool >>

让我猜你在问什么:你的MyClass1MyClass2 看起来一样 (它们都有一个int field1和一个字符串field2)。 现在你有一个Expression> ,类似于:

 Expression> exp1 = x => x.field1 == 100; // x is MyClass1 

你想要另一个看起来相同的表达式,但是它适用于MyClass2

 Expression> exp2 = x => x.field1 == 100; // x is MyClass2 

如果这是你要问的,这是我的答案:

要获取MyClass2的表达式,需要替换exp1所有x ,因为exp1中的所有x都是MyClass1类型。 ExpressionVisitor正是您想要的。

 class MyExpressionVisitor : ExpressionVisitor { public ParameterExpression NewParameterExp { get; private set; } public MyExpressionVisitor(ParameterExpression newParameterExp) { NewParameterExp = newParameterExp; } protected override Expression VisitParameter(ParameterExpression node) { return NewParameterExp; } protected override Expression VisitMember(MemberExpression node) { if (node.Member.DeclaringType == typeof(MyClass1)) return Expression.MakeMemberAccess(this.Visit(node.Expression), typeof(MyClass2).GetMember(node.Member.Name).FirstOrDefault()); return base.VisitMember(node); } } 

访问者将通过(说“访问”)整个表达式,访问所有节点。 当涉及到ParameterExpression节点时,我们更改节点(因为它是MyClass1,我们将其更改为MyClass2,请参阅VisitParameter方法)。 我们需要改变的另一件事是,当访问者来到像x.field1这样的节点时,它正在访问MyClass1的field1,我们也需要修改它(参见VisitMember)。 经过整个exp1之后,我们得到一个全新的exp2,替换了一些节点,这就是我们想要的。

 Expression> exp1 = x => x.field1 == 100; var visitor = new MyExpressionVisitor(Expression.Parameter(typeof(MyClass2), exp1.Parameters[0].Name)); var exp2 = Expression.Lambda> (visitor.Visit(exp1.Body), visitor.NewParameterExp); //the following is for testing var data = new MyClass2(); Console.WriteLine(exp2.Compile()(data)); //False data.field1 = 100; Console.WriteLine(exp2.Compile()(data)); //True 

表达式树是不可变的,所以要做到这一点,你需要遍历整个树,重建它并用等价物替换该类型的任何用途 – 通常是写一个“访问者”。 遇到MemberExpression或MethodCallExpression时,您将检查成员的声明类型 – 如果它是您不想要的,则重新创建它(Expression.PropertyOrField在这里很有用)。

请注意,您不能只在它使用的地方执行此操作; 整个树必须重新生成。 我现在不在电脑上,但如果你愿意我可以稍后做一个例子; 如果您需要此示例,请发表评论。

请注意,由于int / long和char / string不匹配,这有点复杂。

 public CategoryViewModel GetSingle( Expression> where) { Expression> converter = c => ToBll(c); var param = Expression.Parameter(typeof(DAL.EntityModels.Category), "category"); var body = Expression.Invoke(where, Expression.Invoke(converter, param)); var lambda = Expression.Lambda>(body, param); return (CategoryViewModel )_categoryRepository.GetSingle(lambda); } //.............. public T GetSingle(Expression> where) { return this.ObjectSet.Where(where).FirstOrDefault(); } 

您可以将第一个表达式编译为委托,然后将其转换为
NJection.LambdaConverter是一个将委托转换为表达式树的库。