Convert Linq expression "obj => obj.Prop" to "parent => parent.obj.Prop"
I have an existing type expression Expression<Func<T, object>>; it contains values ββsuch as cust => cust.Name.
I also have a parent class with a type field T. I need a method that takes the above as a parameter and generates a new expression that takes the parent class ( TModel) as a parameter. This will be used as an expression parameter for the MVC method.
So it cust => cust.Namebecomes parent => parent.Customer.Name.
Similarly, cust => cust.Address.Stateit becomes parent => parent.Customer.Address.State.
Here is my initial version:
//note: the FieldDefinition object contains the first expression
//described above, plus the MemberInfo object for the property/field
//in question
public Expression<Func<TModel, object>> ExpressionFromField<TModel>(FieldDefinition<T> field)
where TModel: BaseModel<T>
{
var param = Expression.Parameter(typeof(TModel), "t");
//Note in the next line "nameof(SelectedItem)". This is a reference
//to the property in TModel that contains the instance from which
//to retrieve the value. It is unqualified because this method
//resides within TModel.
var body = Expression.PropertyOrField(param, nameof(SelectedItem));
var member = Expression.MakeMemberAccess(body, field.Member);
return Expression.Lambda<Func<TModel, object>>(member, param);
}
, , (.. cust.Address.State cust.Name). var member, - , (Customer), , ().
:
public Expression<Func<TModel, object>> ExpressionFromField<TModel>(FieldDefinition<T> field)
where TModel: BaseModel<T>
{
var param = Expression.Parameter(typeof(TModel), "t");
var body = Expression.PropertyOrField(param, nameof(SelectedItem));
var IWantThis = Expression.ApplyExpressionToField(field.Expression, body);
return Expression.Lambda<Func<TModel, object>>(IWantThis, param);
}
, , .
, , , :
public static Expression<Func<T, TResult>> Compose<T, TIntermediate, TResult>(
this Expression<Func<T, TIntermediate>> first,
Expression<Func<TIntermediate, TResult>> second)
{
return Expression.Lambda<Func<T, TResult>>(
second.Body.Replace(second.Parameters[0], first.Body),
first.Parameters[0]);
}
, :
public class ReplaceVisitor:ExpressionVisitor
{
private readonly Expression from, to;
public ReplaceVisitor(Expression from, Expression to)
{
this.from = from;
this.to = to;
}
public override Expression Visit(Expression ex)
{
if(ex == from) return to;
else return base.Visit(ex);
}
}
public static Expression Replace(this Expression ex,
Expression from,
Expression to)
{
return new ReplaceVisitor(from, to).Visit(ex);
}
, :
Expression<Func<Customer, object>> propertySelector = cust => cust.Name;
, :
Expression<Func<CustomerModel, Customer>> modelSelector = model => model.Customer;
:
Expression<Func<Customer, object> magic = modelSelector.Compose(propertySelector);