這可以通過實施Compose
方法,將採取兩個表達式,並返回充當如果它會調用第一表達式來完成,然後提供作爲參數傳遞給第二:
void Search(IQueryable<Entity> results, string keywords,
Expression<Func<Entity, string>> selector)
{
results = results.Where(selector.Compose(obj => obj.Contains(keywords)));
}
要實現我們想要使用一個輔助方法,讓我們用另一個替換一個表達的所有實例開始:
internal 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 node)
{
return node == from ? to : base.Visit(node);
}
}
public static Expression Replace(this Expression expression,
Expression searchEx, Expression replaceEx)
{
return new ReplaceVisitor(searchEx, replaceEx).Visit(expression);
}
使用該工具是釀回到一起爲lambda更換了一把簡單:
public static Expression<Func<TFirstParam, TResult>>
Compose<TFirstParam, TIntermediate, TResult>(
this Expression<Func<TFirstParam, TIntermediate>> first,
Expression<Func<TIntermediate, TResult>> second)
{
var param = Expression.Parameter(typeof(TFirstParam), "param");
var newFirst = first.Body.Replace(first.Parameters[0], param);
var newSecond = second.Body.Replace(second.Parameters[0], newFirst);
return Expression.Lambda<Func<TFirstParam, TResult>>(newSecond, param);
}
它也似乎很奇怪的查詢過濾項,其中一個字符串與所有的單詞包含在給定的字段中。您似乎更希望獲得包含任意字符串列表的任何的項目。這是不同的,只需要更多的工作。
我們可以使用一個新類,我們將其稱爲PredicateBuilder
來構建一個篩選器,該篩選器採用一堆其他篩選器的邏輯OR
。
void Search(IQueryable<Entity> results, IEnumerable<string> keywords,
Expression<Func<Entity, string>> selector)
{
var finalFilter = keywords.Aggregate(
PredicateBuilder.False<Entity>(),
(filter, keyword) => filter.Or(
selector.Compose(obj => obj.Contains(keyword))));
results = results.Where(finalFilter);
}
我們可以使用之前,像這樣定義的Replace
方法實現這個類:
public static class PredicateBuilder
{
public static Expression<Func<T, bool>> True<T>() { return f => true; }
public static Expression<Func<T, bool>> False<T>() { return f => false; }
public static Expression<Func<T, bool>> Or<T>(
this Expression<Func<T, bool>> expr1,
Expression<Func<T, bool>> expr2)
{
var secondBody = expr2.Body.Replace(expr2.Parameters[0], expr1.Parameters[0]);
return Expression.Lambda<Func<T, bool>>
(Expression.OrElse(expr1.Body, secondBody), expr1.Parameters);
}
public static Expression<Func<T, bool>> And<T>(
this Expression<Func<T, bool>> expr1,
Expression<Func<T, bool>> expr2)
{
var secondBody = expr2.Body.Replace(expr2.Parameters[0], expr1.Parameters[0]);
return Expression.Lambda<Func<T, bool>>
(Expression.AndAlso(expr1.Body, secondBody), expr1.Parameters);
}
}
看看這裏http://stackoverflow.com/a/10283288/1300049。或者,您可以定義一些操作來獲取所需的屬性並將它們傳遞給您的搜索方法 – JleruOHeP
您可以查看一些動態Linq選項。有些使用反射和一些構建表達樹。據我所知,這並不像你希望的那樣直截了當。 –