我有一个现有的类型表达Expression<Func<T, object>>; 它包含类似的值cust => cust.Name。
Expression<Func<T, object>>
cust => cust.Name
我也有一个类型为的父类T。我需要一个接受上述内容作为参数并生成一个将父类(TModel)作为参数的新表达式的方法。这将用作MVC方法的表达参数。
T
TModel
因此,cust => cust.Name成为parent => parent.Customer.Name。
parent => parent.Customer.Name
同样,cust => cust.Address.State变为parent => parent.Customer.Address.State。
cust => cust.Address.State
parent => parent.Customer.Address.State
这是我的初始版本:
//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),而不是包含该成员的项(Address)。
cust.Address.State
cust.Name
var member
Customer
Address
这是我希望可以做的:
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); }
到此为止的任何帮助将不胜感激。
编辑:这被标记为该问题的可能重复;但是,唯一真正的相似之处是解决方案(实际上是相同的)。组成表达式不是通过表达式访问嵌套属性的直观解决方案(除非有人凭一定的经验来指导自己的行为,否则不应该假设这样做)。我还编辑了问题,以指出该解决方案需要适合于MVC方法的参数,这限制了可能的解决方案。
您正在寻找的是能够表达表达式的能力,就像您可以构成函数一样:
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);