我需要一些帮助,我的方法在我的课程中重复了6次,每个方法中唯一改变的是LINQ属性(在示例中为"名字",但我也有一个用于姓氏,公司名称,用户ID,状态).我想帮助重构一下,这样我就可以只使用一种方法,使属性成为动态或传入.
private static IQueryable<MyModel> FilterFirstName(IQueryable<MyModel> query, string searchText, string searchFilter)
{
switch (searchFilter.ToLower())
{
case "contains":
query = query.Where(x => x.FirstName.ToLower().Contains(searchText.ToLower()));
break;
case "does not contain":
query = query.Where(x => !x.FirstName.ToLower().Contains(searchText.ToLower()));
break;
case "starts with":
query = query.Where(x => x.FirstName.StartsWith(searchText, StringComparison.InvariantCultureIgnoreCase));
break;
case "ends with":
query = query.Where(x => x.FirstName.EndsWith(searchText, StringComparison.InvariantCultureIgnoreCase));
break;
case "equals":
query = query.Where(x => x.FirstName.Equals(searchText, StringComparison.InvariantCultureIgnoreCase));
break;
}
return query;
}
Run Code Online (Sandbox Code Playgroud)
您可以做的是使用一种Compose可以将一个表达式与另一个表达式组合的方法:
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);
}
Run Code Online (Sandbox Code Playgroud)
它使用以下方法将一个表达式的所有实例替换为另一个表达式:
public static Expression Replace(this Expression expression,
Expression searchEx, Expression replaceEx)
{
return new ReplaceVisitor(searchEx, replaceEx).Visit(expression);
}
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);
}
}
Run Code Online (Sandbox Code Playgroud)
现在你可以写:
private static IQueryable<MyModel> FilterFirstName(
IQueryable<MyModel> query,
Expression<Func<MyModel, string>> selector,
string searchText,
string searchFilter)
{
switch (searchFilter.ToLower())
{
case "contains":
query = query.Where(selector.Compose(
text => text.ToLower().Contains(searchText.ToLower())));
break;
case "does not contain":
query = query.Where(selector.Compose(
text => !text.ToLower().Contains(searchText.ToLower())));
break;
case "starts with":
query = query.Where(selector.Compose(
text => text.StartsWith(searchText, StringComparison.InvariantCultureIgnoreCase)));
break;
case "ends with":
query = query.Where(selector.Compose(
text => text.EndsWith(searchText, StringComparison.InvariantCultureIgnoreCase)));
break;
case "equals":
query = query.Where(selector.Compose(
text => text.Equals(searchText, StringComparison.InvariantCultureIgnoreCase)));
break;
}
return query;
}
Run Code Online (Sandbox Code Playgroud)
顺便说一句,您实际上应该使用 anenum来表示 的不同类型的过滤器searchFilter,而不是字符串。这将使调用者变得更加容易,因为他们不需要键入精确的字符串,而无需任何好的方法来知道确切的选项是什么,或者提供的选项是否有效。