我需要一些帮助,我的方法在我的课程中重复了6次,每个方法中唯一改变的是LINQ属性(在示例中#34;名字和# 34;,但我也有一个姓氏,公司名称,用户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;
}
答案 0 :(得分:2)
你可以做的是使用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);
}
使用以下方法将一个表达式的所有实例替换为另一个:
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);
}
}
现在你可以写:
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;
}
另外,您应该使用enum
来表示searchFilter
的不同类型的过滤器,而不是字符串。这将使调用者更容易,因为他们不需要输入精确的字符串,而无需知道确切的选项是什么,或者提供的选项是否有效。
答案 1 :(得分:-1)
此版本允许您将属性传递给过滤器,如下所示:
Filter(models, (MyModel m) => m.FirstName, "Joe", "contains");
Filter(models, (MyModel m) => m.LastName, "Smith", "contains");
private static IQueryable<MyModel> Filter(IQueryable<MyModel> query, Func<MyModel, string> property, string searchText, string searchFilter)
{
switch (searchFilter.ToLower())
{
case "contains":
query = query.Where(x => property(x).ToLower().Contains(searchText.ToLower()));
break;
case "does not contain":
query = query.Where(x => !property(x).ToLower().Contains(searchText.ToLower()));
break;
case "starts with":
query = query.Where(x => property(x).StartsWith(searchText, StringComparison.InvariantCultureIgnoreCase));
break;
case "ends with":
query = query.Where(x => property(x).EndsWith(searchText, StringComparison.InvariantCultureIgnoreCase));
break;
case "equals":
query = query.Where(x => property(x).Equals(searchText, StringComparison.InvariantCultureIgnoreCase));
break;
}
return query;
}
答案 2 :(得分:-1)
我会做以下一项或多项:
反映并缓存属性查找&#34;方法&#34; (&#34; x.FirstName&#34;位可以很容易地通过反射来处理
选择&#34;选择器&#34;函数并将其应用于拾取目标对象
将此作为扩展方法
代码:
public static class FilterPerson
{
static IQueryable<Person> FilterPerson(
this IQueryable<Person> query,
FilterString filter,
Func<Person, string> selector,
string searchText)
{
var enumerableQuery = query.AsEnumerable();
switch (filter)
{
case FilterString.Contains:
enumerableQuery = enumerableQuery.Where(x => selector(x).ToLowerInvariant().Contains(searchText.ToLowerInvariant()));
break;
case FilterString.DoesNotContain:
enumerableQuery = enumerableQuery.Where(x => !selector(x).ToLower().Contains(searchText.ToLower()));
break;
case FilterString.StartsWith:
enumerableQuery = enumerableQuery.Where(x => selector(x).StartsWith(searchText, StringComparison.InvariantCultureIgnoreCase));
break;
case FilterString.EndsWith:
enumerableQuery = enumerableQuery.Where(x => selector(x).EndsWith(searchText, StringComparison.InvariantCultureIgnoreCase));
break;
case FilterString.Equals:
enumerableQuery = enumerableQuery.Where(x => selector(x).Equals(searchText, StringComparison.InvariantCultureIgnoreCase));
break;
}
return enumerableQuery.AsQueryable();
}
}
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string PhoneNumber { get; set; }
}
public enum FilterString
{
StartsWith,
Contains,
DoesNotContain,
EndsWith,
Equals
}
答案 3 :(得分:-5)
如果在代码中调用了6次,并且其中有5个路径,我会说方法本身会引入不必要的耦合,应该删除。