构造具有链式属性的表达式树?
Construct expression tree with chained properties?
我有一个接受 Expression<Func<T, string>>
的方法,例如 x => x.Name
和一个术语,以及 returns x => x.Name.Contains(term)
:
给定模型;
class X
{
public Y Y {get; set;}
}
class Y
{
public string Z {get; set;}
}
它适用于 GenerateForMember<Y>(y => y.Z, "foobar")
,但目前不适用于 GenerateForMember<X>(x => x.Y.Z, "foobar")
。它给出了例外
'Z' is not a member of 'UserQuery+X'
如何更新我的方法以使用链式属性?
方法如下:
protected Expression<Func<T, bool>> GenerateForMember<T>(Expression<Func<T,string>> expression, string term)
{
var type = typeof(T);
var memberExpression = ((expression.Body.NodeType == ExpressionType.Convert)
? ((UnaryExpression)expression.Body).Operand
: expression.Body) as MemberExpression;
ParameterExpression parameter = Expression.Parameter(type, type.Name.ToLower());
MemberExpression member = Expression.PropertyOrField(parameter, memberExpression.Member.Name);
var propertyInfo = memberExpression.Member as PropertyInfo;
var memberType = propertyInfo == null
? ((FieldInfo) memberExpression.Member).FieldType
: propertyInfo.PropertyType;
ConstantExpression constant = Expression.Constant(term, typeof(string));
MethodInfo method = typeof(string).GetMethod("Contains", new[] { typeof(string) });
var containsMethodExp = Expression.Call(member, method, constant);
return Expression.Lambda<Func<T, bool>>(containsMethodExp, parameter);
}
您正在剖析原始表达式,然后重新构造它。这是没有必要的。您可以直接使用 expression.Body
来创建方法调用。像这样,它应该适用于任何 lambda 表达式。
var type = typeof(T);
ParameterExpression parameter = Expression.Parameter(type, type.Name.ToLower());
ConstantExpression constant = Expression.Constant(term, typeof(string));
MethodInfo method = typeof(string).GetMethod("Contains", new[] { typeof(string) });
var containsMethodExp = Expression.Call(expression.Body, method, constant);
return Expression.Lambda<Func<T, bool>>(containsMethodExp, parameter);
试试这个:
protected Expression<Func<T, bool>> GenerateForMember<T>(Expression<Func<T, string>> expression, string term)
{
ConstantExpression constant = Expression.Constant(term, typeof(string));
MethodInfo method = typeof(string).GetMethod("Contains", new[] { typeof(string) });
var containsMethodExp = Expression.Call(expression.Body, method, constant);
return Expression.Lambda<Func<T, bool>>(containsMethodExp, expression.Parameters[0]);
}
我有一个接受 Expression<Func<T, string>>
的方法,例如 x => x.Name
和一个术语,以及 returns x => x.Name.Contains(term)
:
给定模型;
class X
{
public Y Y {get; set;}
}
class Y
{
public string Z {get; set;}
}
它适用于 GenerateForMember<Y>(y => y.Z, "foobar")
,但目前不适用于 GenerateForMember<X>(x => x.Y.Z, "foobar")
。它给出了例外
'Z' is not a member of 'UserQuery+X'
如何更新我的方法以使用链式属性?
方法如下:
protected Expression<Func<T, bool>> GenerateForMember<T>(Expression<Func<T,string>> expression, string term)
{
var type = typeof(T);
var memberExpression = ((expression.Body.NodeType == ExpressionType.Convert)
? ((UnaryExpression)expression.Body).Operand
: expression.Body) as MemberExpression;
ParameterExpression parameter = Expression.Parameter(type, type.Name.ToLower());
MemberExpression member = Expression.PropertyOrField(parameter, memberExpression.Member.Name);
var propertyInfo = memberExpression.Member as PropertyInfo;
var memberType = propertyInfo == null
? ((FieldInfo) memberExpression.Member).FieldType
: propertyInfo.PropertyType;
ConstantExpression constant = Expression.Constant(term, typeof(string));
MethodInfo method = typeof(string).GetMethod("Contains", new[] { typeof(string) });
var containsMethodExp = Expression.Call(member, method, constant);
return Expression.Lambda<Func<T, bool>>(containsMethodExp, parameter);
}
您正在剖析原始表达式,然后重新构造它。这是没有必要的。您可以直接使用 expression.Body
来创建方法调用。像这样,它应该适用于任何 lambda 表达式。
var type = typeof(T);
ParameterExpression parameter = Expression.Parameter(type, type.Name.ToLower());
ConstantExpression constant = Expression.Constant(term, typeof(string));
MethodInfo method = typeof(string).GetMethod("Contains", new[] { typeof(string) });
var containsMethodExp = Expression.Call(expression.Body, method, constant);
return Expression.Lambda<Func<T, bool>>(containsMethodExp, parameter);
试试这个:
protected Expression<Func<T, bool>> GenerateForMember<T>(Expression<Func<T, string>> expression, string term)
{
ConstantExpression constant = Expression.Constant(term, typeof(string));
MethodInfo method = typeof(string).GetMethod("Contains", new[] { typeof(string) });
var containsMethodExp = Expression.Call(expression.Body, method, constant);
return Expression.Lambda<Func<T, bool>>(containsMethodExp, expression.Parameters[0]);
}