I have a C# application with a user interface that contains options for the type of search a user can perform. The options are ‘multiple terms’ (splits the search term on spaces), ‘case sensitive’, and ‘regular expression’. More options may be added in the future.
The options are stored in the properties IsMultipleTerms, IsCaseSensitive, and IsRegularExpression.
Each combination of options has a different search predicate, and search predicates are defined like so:
private bool SearchCaseInsensitive(string field)
{
return field.ToLower().Contains(_searchTermLower);
}
private bool SearchCaseInsensitiveMultiple(string field)
{
return _searchTermsLower.All(field.ToLower().Contains);
}
I filter the list like so:
var predicate = GetFilterPredicate();
SearchResults.Where(predicate);
I currently achieve the lookup by using a class called 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;
}
}
I create a list of them and then query it:
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();
}
Is there a cleaner way to achieve this? I feel like I may be missing an important concept.
At least for the check part you could use an Enum with the
[Flags]attribute to create bit field. That might be a little more extensible if you add more methods in the future. You could then use a simple lookup table and do away with thePredicateOptionSetclass. Example:…
….