2011-06-22 16 views
1

私はユーザーが実行できる検索の種類のオプションを含むユーザーインターフェイスを持つ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

'PredicateOptionSet'とは何ですか? – asawyer

+0

質問本体に追加しました、ごめんなさい:) – Beau

+1

Fool の代りにPredicate を代入することができます。おそらく、それは既に何か特定のものを参照しているので、パラメータ述語に名前をつけないでください。 –

答えて

1

少なくともチェック部分では、[Flags]属性のEnumを使用してビットフィールドを作成することができます。将来的にメソッドを追加すると、それはもう少し拡張性があるかもしれません。その後、単純なルックアップテーブルを使用して、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]); 
0

オプションごとに1つの機能を作ってから(Where(...)呼び出しで)チェーンすることができたようです。そうすれば、あなたは4つではなく3つの方法しか持たない。また、必要な場合は、より小さな操作をより多くの方法で組み合わせることもできます。

1

たぶん私はそれが間違って表示さが、現在あなたが2つの根本的に異なる検索方法があります:ノーマルと正規表現。両方の戦略は、大文字と小文字のどちらかを選択するオプションをサポートしますが、これは戦略のパラメータになる可能性があります。とにかく検索用語を分割してから、単純な検索戦略(ANDまたはORで検索を組み合わせる)のいずれかに既に委任することができるので、マルチマッチの問題は既に多少特殊です。

これらの側面のそれぞれの組み合わせに対して別々のFunc実装を作成することは、「過度の不安」を感じます。将来的にいくつかのオプションが存在するようであれば、これらのオプションを「同等」に扱う一般化されたアプローチを見つけることは本当に魅力的ですが、一方でこれらのオプションは全く異なる動作をします。また、将来の拡張のために、別の実装の組み合わせの爆発に遭遇することもあります。