我有一个带有用户界面的C#应用程序,其中包含用户可以执行的搜索类型的选项。选项是“多个术语”(在空格上拆分搜索词),“区分大小写”和“正则表达式”。将来可能会添加更多选项。
选项存储在属性IsMultipleTerms,IsCaseSensitive和IsRegularExpression中。
每个选项组合都有不同的搜索谓词,搜索谓词的定义如下:
private bool SearchCaseInsensitive(string field)
{
return field.ToLower().Contains(_searchTermLower);
}
private bool SearchCaseInsensitiveMultiple(string field)
{
return _searchTermsLower.All(field.ToLower().Contains);
}
我像这样过滤列表:
var predicate = GetFilterPredicate();
SearchResults.Where(predicate);
我目前通过使用名为SearchPredicateOptionSet的类来实现查找:
public class PredicateOptionSet
{
public bool IsCaseSensitive { get; set; }
public bool IsRegularExpression { get; set; }
public bool IsMultipleTerms { get; set; }
public Func<SearchResult, bool> Predicate { get; set; }
public PredicateOptionSet(bool isCaseSensitive, bool isRegularExpression, bool isMultipleTerms,
Func<SearchResult, bool> predicate)
{
IsCaseSensitive = isCaseSensitive;
IsRegularExpression = isRegularExpression;
IsMultipleTerms = isMultipleTerms;
Predicate = predicate;
}
}
我创建了一个列表,然后查询它:
private readonly List<PredicateOptionSet> _predicates;
public MainWindow()
{
_predicates = new List<PredicateOptionSet>
{
new PredicateOptionSet(true, false, false, result => Search(result.Name)),
new PredicateOptionSet(false, false, false, result => SearchCaseInsensitive(result.Name)),
new PredicateOptionSet(true, false, true, result => SearchMultiple(result.Name)),
new PredicateOptionSet(false, false, true, result => SearchCaseInsensitiveMultiple(result.Name)),
};
}
private Func<SearchResult, bool> GetFilterPredicate()
{
var predicate = from p in _predicates
where p.IsCaseSensitive == IsCaseSensitive &&
p.IsMultipleTerms == IsMultipleTerms &&
p.IsRegularExpression == IsRegularExpression
select p.Predicate;
return predicate.First();
}
有更清洁的方法来实现这一目标吗?我觉得我可能错过了一个重要的概念。
答案 0 :(得分:1)
至少对于检查部分,您可以使用具有[Flags]
属性的枚举来创建位字段。如果您将来添加更多方法,那可能会更具扩展性。然后,您可以使用简单的查找表并取消PredicateOptionSet
类。例如:
[Flags]
public enum PredicateOption
{
IsCaseSensitive, IsRegularExpression, IsMultipleTerms
};
...
public Dictionary<PredicateOption, Func<SearchResult, bool>> _predicates
= new Dictionary<PredicateOption, Func<SearchResult, bool>>();
_predicates.Add(PredicateOption.IsCaseSensitive, result => Search(result.Name));
_predicates.Add(PredicateOption.IsCaseSensitive | PredicateOption.IsMultipleTerms,
result => SearchCaseInsensitiveMultiple(result.Name));
...
PredicateOption option = PredicateOption.IsCaseSensitive | PredicateOption.IsMultipleTerms;
SearchResults.Where(_predicates[option]);
答案 1 :(得分:1)
也许我看错了,但目前你有2种根本不同的搜索策略:正常和正则表达式。这两种策略都支持一种选项,无论是否区分大小写,但这可能是策略的一个参数。多匹配问题已经有点特殊了,因为您无论如何必须首先拆分搜索词,然后您可以将其委托回一个简单的搜索策略(将搜索与AND或OR组合)。
为这些方面的每个组合创建单独的Func实现感觉有点“过度杀伤”。如果将来会有更多的选择,那么找到一种处理这些选项“相等”的通用方法确实很诱人,但另一方面,这些选项的行为却截然不同。对于未来的扩展,您也会遇到不同实现的组合爆炸。
答案 2 :(得分:0)
似乎你可以为每个选项创建一个函数,然后将它们链接起来(通过Where(...)调用)。这样,您只有三种方法而不是四种方法。此外,如果需要,您可以以更多方式组合较小的操作。