谓词的查找表?

时间:2011-06-22 18:43:35

标签: c# .net linq lookup predicate

我有一个带有用户界面的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 个答案:

答案 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(...)调用)。这样,您只有三种方法而不是四种方法。此外,如果需要,您可以以更多方式组合较小的操作。