Позвольте мне угадать, что вы спрашиваете: ваши MyClass1
и MyClass2
выглядят одинаково (они оба имеют int field1 и string 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
, потому что все x
в exp1 имеют тип 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
, он посещает поле 1 в MyClass1
, мы также должны изменить его (см. 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