Let me guess what you are asking: Your MyClass1
and MyClass2
look the same (they both have an int field1 and a string field2). Now you have an Expression<Func<MyClass1,bool>>
, something like:
Expression<Func<MyClass1, bool>> exp1 = x => x.field1 == 100; // x is MyClass1
And you want another expression, which looks the same, but it's for MyClass2
:
Expression<Func<MyClass2, bool>> exp2 = x => x.field1 == 100; // x is MyClass2
If this is what you are asking, here is my answer:
To get the expression for MyClass2
, you need to replace all x
in exp1
, because all x
in exp1 are of type MyClass1
. ExpressionVisitor is exactly what you want.
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);
}
}
The visitor will go through(say "visit") the whole expression, visit all the nodes. When it comes to an ParameterExpression
node, we change the node (because it's MyClass1, we change it to MyClass2, see VisitParameter method). Another thing we need to change is, when the visitor comes to a node like x.field1
, it's visiting the field1 in MyClass1
, we need to modify it too(see VisitMember). After going through the whole exp1, we get a totally new exp2, with some nodes replaced, that's what we want.
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