更新:
我会尽力解释我的意思。
有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<MyClass1, bool>> where, //other parameters)
{
//some operations
//...............
//need to call method2(Expression<Func<MyClass2, bool>>)
// BUT! How do I convert Expression<Func<MyClass1, bool>>
// to Expression<Func<MyClass2, bool>>
}
void method2(Expression<Func<MyClass2, bool>> where, //other parameters)
{
//some operations
}
如何将Expression >转换为Expression >
最佳答案
让我猜猜您在问什么:您的MyClass1
和MyClass2
看起来相同(它们都有一个int field1和一个字符串field2)。现在您有了一个Expression<Func<MyClass1,bool>>
,类似于:
Expression<Func<MyClass1, bool>> exp1 = x => x.field1 == 100; // x is MyClass1
您需要另一个看起来相同的表达式,但它用于
MyClass2
:Expression<Func<MyClass2, bool>> exp2 = x => x.field1 == 100; // x is MyClass2
如果这是您的要求,这是我的答案:
要获取
MyClass2
的表达式,您需要替换x
中的所有exp1
,因为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<Func<MyClass1, bool>> exp1 = x => x.field1 == 100;
var visitor = new MyExpressionVisitor(Expression.Parameter(typeof(MyClass2),
exp1.Parameters[0].Name));
var exp2 = Expression.Lambda<Func<MyClass2, bool>>
(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