2017-06-23 3 views
2

Ich versuche, eine elegante und erweiterbare Möglichkeit der Abfrage eines Wörterbuchs zu erstellen, das eine Enumeration einer Reihe von Zeichenfolgen zuordnet.Elegante Möglichkeit zum Abfragen eines Wörterbuchs in C#

So habe ich diese Klasse SearchFragments, die das Wörterbuch enthält. Ich möchte dann eine Methode, bei der Verbraucher dieser Klasse einfach "HasAny" fragen können, und das ist das Bit, wo ich kämpfe, einfach einige Abfrage wie Ausdruck übergeben und die boolesche Antwort zurückbekommen.

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; 
    } 
} 

Das Problem mit der Art und Weise dies derzeit ist, ist, dass die Verbraucher von dieser Klasse müssen jetzt ein IEnumerable<SearchFragmentEnum> konstruieren, die ziemlich chaotisch sein können.

Was ich suche, ist, dass die verzehr Code in der Lage sein wird, etwas entlang der Linien von schreiben:

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

Aber wo dieses Argument Liste in der Größe variieren kann (ohne mich Verfahren Überlastungen schreiben in die SearchFragments Klasse für jede mögliche Kombination (so dass, wenn neue Werte in die SearchFragmentEnum zu einem späteren Zeitpunkt hinzugefügt werden, werde ich nicht die Klasse zu aktualisieren.

+1

Mögliche Duplikat [Warum die params Schlüsselwort?] (https://stackoverflow.com/questions/7580277/why-use-the-params-keyword) – krillgar

+4

versuchen Sie dies: 'Rückkehr von? .Any (_fragments.ContainsKey) ?? false; ' – Sergey

Antwort

5

können Sie verwenden params[]

public bool HasAny(params SearchFragmentEnum[] of) 
{ ... 

Hinweis: Sie wissen, dass LIN (Q) -Abfragen nur eine Quelle abfragen und niemals irgendwelche Nebenwirkungen verursachen sollten? Aber Ihre Abfrage nicht erhöhen unnötig die ganze Zahl:

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

Statt dessen verwenden (was auch effizienter und besser lesbar):

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

Eine noch effizientere Alternative dazu ist Sergey's Idee :

+0

Danke, das wusste ich nicht, macht Sinn. Ich denke, es ist die gleiche Art von logischem Prinzip wie die einzige Verantwortung von SOLID. Ich meine, was ich kompiliert habe, aber Sie heben einen gültigen Punkt hervor. Ich werde das, was Sie hier gesagt haben, anwenden :-) –

+0

Bin ich richtig, wenn ich bedenke, dass Intersect (zumindest konzeptionell) mit SQL Inner Join vergleichbar ist? Damit meine ich, dass es eine boolesche Schnittmenge beider Sammlungen gibt? –

+1

@ThomasCook: 'Schnittmenge 'ist eine Set-Methode, die die Schnittmenge zweier Sequenzen erstellt (indem Duplikate ignoriert werden). Aber da es verzögert ausgeführt wird, muss es nicht die gesamte Kreuzung erstellen. Das 'Any' am Ende hört auf, sobald ein gefunden wurde. Wenn Sie wissen möchten, wie viele sich schneiden, können Sie 'Count' anstelle von' Any' anhängen. Aber dann muss alles bewertet werden. –

3

Für Variablengrößen in C# verwenden Sie die params Stichwort: public int HasAny (params SearchFragmentEnum [] von)

Die .Net-API bietet aus Leistungsgründen normalerweise ein paar Überlastungen; Die übergebenen Parameter werden in ein neues Array kopiert. Überflüssige Überlastungen für die häufigsten Fälle vermeiden dies.

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

Statt params verwenden könnten Sie auch Ihre Enum mit dem [Flags] Attribut betrachten Markierung. Parameter könnten dann wie HasAny(SearchFragmentEnum.Name | SearchFragmentEnum.PhoneNumber übergeben werden. In StackOverflow reichlich vorhandene Beispiele (z. B. Using a bitmask in C#)

3

Verwenden Sie das Schlüsselwort params, um eine unterschiedliche Anzahl von Argumenten zuzulassen. Außerdem können Sie Ihren Code vereinfachen, indem Sie das kleinere Array of überschleifen. Auch Sie ein Wörterbuch verwenden, die O (1) Schlüsselprüfung hat, so ist es uneccessary eine innere Schleife zu haben:

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

oder kürzer mit LINQ

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

Große Lösung! – mjwills

Verwandte Themen