Таблица поиска предикатов? - PullRequest
1 голос
/ 22 июня 2011

У меня есть приложение 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();
}

Есть ли более чистый способ добиться этого? Я чувствую, что могу упустить важную концепцию.

Ответы [ 3 ]

1 голос
/ 22 июня 2011

По крайней мере, для проверочной части вы можете использовать Enum с атрибутом [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 голос
/ 23 июня 2011

Возможно я вижу это неправильно, но в настоящее время у вас есть 2 принципиально разные стратегии поиска: обычная и регулярное выражение.Обе стратегии поддерживают параметр, учитывающий либо регистр, либо нет, но это может быть параметром стратегии.Проблема множественного совпадения уже является чем-то особенным, потому что в любом случае вам сначала нужно разделить поисковый термин, а затем вы уже можете делегировать одну из простых стратегий поиска (комбинируя поиск либо с AND, либо с OR).

Создание отдельной реализации Func для каждой комбинации этих аспектов выглядит немного «излишним».Если в будущем появятся еще несколько вариантов, действительно соблазнительно найти обобщенный подход, который обрабатывает эти параметры «равными», но, с другой стороны, эти параметры ведут себя совершенно по-другому.Кроме того, на будущих расширениях вы столкнетесь с комбинаторным взрывом различных реализаций.

0 голосов
/ 22 июня 2011

Кажется, что вы можете создать одну функцию для каждой опции, а затем объединить их в цепочку (посредством вызовов Where (...)) Таким образом, у вас есть только три метода вместо четырех. Кроме того, вы можете комбинировать операции меньшего размера, если вам это необходимо.

...