2015-10-05 73 views
0

我有接受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

你解剖原始表達式,稍後再重新構建它。這不是必需的。您可以直接使用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); 
+0

我解剖和重建的原因是因爲參數名稱可能不匹配。但是我可以使用我已經在其他地方使用的訪問者對其進行重命名,然後使用您的方法。謝謝。 – Andre

+0

@Andre,我建議的方法重用了原始表達式中的相同參數。 –

+0

@YacoubMassad對不起,我還不夠清楚。調用這個函數的函數可能會接收多個成員和術語,然後加入它們。例如,傳遞'x => x.Foo'和'y => y.Bar'並且術語「foo」,「bar」將導致x =>(x.Foo.Contains(「foo」)|| x .Foo.Contains(「bar」))&&(x.Bar.Contains(「foo」)|| x.Bar.Contains(「bar」))' – Andre

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