将Linqexpression式“obj => obj.Prop”转换为“parent => parent.obj.Prop”
我有一个现有的expression式typesExpression<Func<T, object>>
; 它包含像cust => cust.Name
这样的值。
我也有一个types为T
的字段的父类。 我需要一个方法,接受上述作为参数,并生成一个新的expression式,父类( TModel
)作为参数。 这将被用作MVC方法的expression式参数。
因此, cust => cust.Name
变为parent => parent.Customer.Name
。
同样, 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
)的项目。
这是我希望我能做的事情:
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); }
任何帮助到这一点将不胜感激。
编辑:这被标记为这个问题的可能重复; 然而,唯一真正的相似之处是解决scheme(实际上是相同的)。 编写expression式不是通过expression式访问嵌套属性的直观解决scheme(除非用户的input是由某些经验引导的,不应该被假设)。 我还编辑了这个问题,注意到解决scheme需要适合MVC方法的参数,这限制了可能的解决scheme。
你正在寻找的是组成expression式的能力,就像你可以编写函数一样:
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]); }
这依赖于下面的方法来replace一个expression式的所有实例:
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); }
你现在可以select一个属性的expression式:
Expression<Func<Customer, object>> propertySelector = cust => cust.Name;
以及从模型中select该对象的expression式:
Expression<Func<CustomerModel, Customer>> modelSelector = model => model.Customer;
并撰写它们:
Expression<Func<Customer, object> magic = modelSelector.Compose(propertySelector);