I have a method like this:
private bool Method_1(Expression<Func<IPerson, bool>> expression)
{
/* Some code that will call Method_2 */
}
In this method I want to change the IPerson
type to another type. I want to call another method that looks like this:
private bool Method_2(Expression<Func<PersonData, bool>> expression)
{
/* Some code */
}
So, in method_1
I need to change IPerson
to PersonData
. How can I do this?
Edit:
When I call: Method_1(p => p.Id == 1)
I want to 'save' the condition (p.Id == 1
) but I want to execute this condition on another type, namely IPerson
. So, I need to alter the expression or create a new expression with IPerson
It is easy if you use .net 4 (update: as noted in comment ExpressionVisitor
was added in version 4 not 4.5) it would require some googling for older frameworks:
There are some assumptions but I think they are valid for your DTO and Entity scenario - properties accessed must match.
class PersonData
{
public bool Prop { get; set; }
}
interface IPerson
{
bool Prop { get; set; }
}
In .net 4 there is ExpressionVisitor
class defined that makes this a lot easier if you use older one then you need to write or find implementation of it:
class Visitor<T> : ExpressionVisitor
{
ParameterExpression _parameter;
//there must be only one instance of parameter expression for each parameter
//there is one so one passed here
public Visitor(ParameterExpression parameter)
{
_parameter = parameter;
}
//this method replaces original parameter with given in constructor
protected override Expression VisitParameter(ParameterExpression node)
{
return _parameter;
}
//this one is required because PersonData does not implement IPerson and it finds
//property in PersonData with the same name as the one referenced in expression
//and declared on IPerson
protected override Expression VisitMember(MemberExpression node)
{
//only properties are allowed if you use fields then you need to extend
// this method to handle them
if (node.Member.MemberType != System.Reflection.MemberTypes.Property)
throw new NotImplementedException();
//name of a member referenced in original expression in your
//sample Id in mine Prop
var memberName = node.Member.Name;
//find property on type T (=PersonData) by name
var otherMember = typeof(T).GetProperty(memberName);
//visit left side of this expression p.Id this would be p
var inner = Visit(node.Expression);
return Expression.Property(inner, otherMember);
}
}
Proof of concept:
class Program
{
static void Main()
{
//sample expression
Expression<Func<IPerson, bool>> expression = x => x.Prop;
//parameter that will be used in generated expression
var param = Expression.Parameter(typeof(PersonData));
//visiting body of original expression that gives us body of the new expression
var body = new Visitor<PersonData>(param).Visit(expression.Body);
//generating lambda expression form body and parameter
//notice that this is what you need to invoke the Method_2
Expression<Func<PersonData, bool>> lambda = Expression.Lambda<Func<PersonData, bool>>(body, param);
//compilation and execution of generated method just to prove that it works
var boolValue = lambda.Compile()(new PersonData());
}
}
Note that this will work for simple expressions. If you need to handle x.Prop.Prop1 < 3
then you need to extend this further.