用链接属性构造表达式树?

时间:2015-10-05 20:58:44

标签: c# expression-trees

我有一个接受Expression<Func<T, string>>的方法,例如x => x.Name和一个字词,并返回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'不是'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);
}

2 个答案:

答案 0 :(得分:2)

您正在剖析原始表达式,然后再重新构建它。这不是必需的。您可以直接使用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);

答案 1 :(得分:1)

试试这个:

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]);
}