2017-06-23 4 views
2

私は、列挙型を文字列のセットにマップする、辞書を照会するエレガントで拡張可能な方法を作成しようとしています。C#の辞書を照会するエレガントな方法

私はこのクラスに辞書を持っているSearchFragmentsを持っています。次に、このクラスの消費者が単に「HasAny」を尋ねることができ、これが私が苦労しているところのビットで、表現のようないくつかのクエリを渡してブール型の答えを返します。

public class SearchFragments 
{ 
    private readonly IDictionary<SearchFragmentEnum, IEnumerable<string>> _fragments; 

    public SearchFragments() 
    { 
     _fragments = new Dictionary<SearchFragmentEnum, IEnumerable<string>>(); 
    } 

    public bool HasAny(IEnumerable<SearchFragmentEnum> of) 
    { 
     int has = 0; 
     _fragments.ForEach(x => of.ForEach(y => has += x.Key == y ? 1 : 0)); 
     return has >= 1; 
    } 
} 

これは現在の方法の問題点は、このクラスの消費者は今、非常に厄介なことができIEnumerable<SearchFragmentEnum>を構築しなければならないということです。私が探しています何

がかかりコードはの線に沿って何かを書くことができるようになるということです。

searchFragments.HasAny(SearchFragmentEnum.Name, SearchFragmentEnum.PhoneNumber) 

しかし、その引数リストは、私は方法のオーバーロードを記述することなく、(大きさを変えることができます新しい値が将来の日付でSearchFragmentEnumに追加された場合、私はクラスを更新する必要がないように、すべての可能な組み合わせのためのSearchFragmentsクラス(。

+1

が重複する可能性を持つ

public bool HasAny(params SearchFragmentEnum[] of) { foreach(var o in of) { if (this._fragments.ContainsKey(o)) return true; } return false; } 

または短い:内側のループを持つことuneccessaryあるので、また、あなたは、O(1)キーチェックを持っている辞書を使用していますparamsキーワード?](https://stackoverflow.com/questions/7580277/why-use-the-params-keyword) – krillgar

+4

これを試してください: 'return??Any(_fragments.ContainsKey)??偽; ' – Sergey

答えて

5

あなたはparams[]

を使用することができます

Sidenote:LIN(Q)クエリはソースを照会するだけで、副作用が発生しないことは知っていますか?しかし、あなたのクエリが不必要に整数をインクリメントん:これまでにも、より効率的な代替がSergey'sアイデアです

return _fragments.Keys.Intersect(of).Any(); 

_fragments.ForEach(x => of.ForEach(y => has += x.Key == y ? 1 : 0)); 

は代わりに、これを(また、より効率的で、より読みやすくしている)を使用します:

return of?.Any(_fragments.ContainsKey) == true; 
+0

ありがとう、私はそれを知らなかった、それはソリッドからの単一の責任と同じ種類の論理的原理だと思います。私はコンパイルしたものを意味するが、有効なポイントを挙げる。私はここであなたが言ったことを適用します:-) –

+0

交差は、(少なくとも概念的に)SQL内部結合に類似していると思うのですか?これにより、両方のコレクションのブール値の交差が行われることを意味しますか? –

+1

@ThomasCook: 'Intersect'は、(重複を無視して)2つのシーケンスの共通部分を構築する設定メソッドです。しかし、それは実行されて延期されているので、全体の交差点を構築する必要はありません。最後に「Any」が見つかるとすぐに停止します。交差する数を知りたければ、 'Any'の代わりに' Count'を追加することができます。しかし、すべてが評価されなければならない。 –

3

可変サイズの引数の場合は、paramsキーワード: public int HasAny(params SearchFragmentEnum [] of)

.Net APIは通常、パフォーマンス上の理由から、これをいくつかオーバーロードします。渡されたパラメータは新しい配列にコピーされます。最も一般的なケースで明示的にオーバーロードを提供することで、これを回避できます。

public int HasAny(SearchfragmentEnum of1) 
public int HasAny(SearchFragmentEnum of1, SearchFragmentEnum of2) 
etc. 

の代わりにあなたも[Flags]属性を使用して列挙型をマーキング検討することもできのparamsを使用。パラメータはHasAny(SearchFragmentEnum.Name | SearchFragmentEnum.PhoneNumberのように渡すことができます。 StackOverflowで豊富な例(Using a bitmask in C#

3

さまざまな数の引数を許可するには、paramsキーワードを使用します。さらに、小さなof配列をループすることで、コードを単純化することができます。 [なぜ使うのLINQ

public bool HasAny(params SearchFragmentEnum[] of) { 
    return of?.Any(_fragments.ContainsKey) ?? false; 
} 
+0

すばらしい解決策! – mjwills

関連する問題