Frage .NET: Switch vs Wörterbuch für String-Schlüssel


Ich habe eine Situation, in der ich ein Geschäftsobjekt mit ungefähr 15 Eigenschaften verschiedener Typen habe. Das Business-Objekt muss auch eine Schnittstelle implementieren, die die folgende Methode hat:

object GetFieldValue(string FieldName);

Ich kann 2 Möglichkeiten sehen, diese Methode zu implementieren:

Verwenden Sie eine switch-Anweisung:

switch ( FieldName )
{
    case "Field1": return this.Field1;
    case "Field2": return this.Field2;
    // etc.
}

Verwenden Sie ein Wörterbuch (SortedDictionary oder HashTable?):

return this.AllFields[FieldName];

Was wäre effizienter?

Hinzugefügt: Vergessen zu sagen. Diese Methode dient zum Anzeigen des Objekts in einem Raster. Das Raster enthält für jede dieser Eigenschaften eine Spalte. Es wird routinemäßig Grids mit etwas über 1000 Elementen geben. Deshalb mache ich mir Sorgen um die Leistung.

Hinzugefügt 2:

Hier ist eine Idee: ein hybrider Ansatz. Erstellen Sie ein statisches Wörterbuch mit Schlüsseln als Eigenschaftsnamen und Werten als Indizes im Array. Das Wörterbuch wird nur einmal beim Start der Anwendung gefüllt. Jede Objektinstanz hat ein Array. Also wäre die Suche wie folgt:

return this.ValueArray[StaticDictionary[FieldName]];

Der Wörterbuchfüllalgorithmus kann Reflexion verwenden. Die Eigenschaften selbst werden dann entsprechend umgesetzt:

public bool Field1
{
    get
    {
        object o = this.ValueArray[StaticDictionary["Field1"]]; 
        return o == null ? false : (bool)o;
    }
    set
    {
        this.ValueArray[StaticDictionary["Field1"]] = value;
    }
}

Kann jemand irgendwelche Probleme damit sehen?

Es kann auch einen Schritt weiter gehen und das ValueArray / StaticDictionary kann in einem separaten generischen Typ platziert werden ValueCollection<T>, woher T würde den Typ für die Reflexion angeben. ValueCollection behandelt auch den Fall, wenn noch kein Wert festgelegt wurde. Eigenschaften könnten dann einfach wie folgt geschrieben werden:

public bool Field1
{
    get
    {
        return (bool)this.Values["Field1"];
    }
    set
    {
        this.Values["Field1"] = value;
    }
}

Und am Ende frage ich mich wieder, ob eine einfache switch-Anweisung nicht schneller und einfacher zu warten ist ....


10
2017-08-26 11:34


Ursprung


Antworten:


switch:      good efficiency, least maintainable
dictionary:  good efficiency, better maintainability
reflection:  least efficient, best maintainability

Tipp: Ignorieren Sie die Effizienz und sorgen Sie sich nur um Wartbarkeit, es sei denn, Sie haben die Leistung tatsächlich getestet und festgestellt, dass sie ein Problem darstellt.

Ich sage nicht, Reflektion ist Ihre einzige Wahl, nur dass Sie Eigenschaften nach Bedarf hinzufügen / entfernen und umbenennen können und die Switch-Anweisung oder das Wörterbuch nicht synchron halten müssen.


21
2017-08-26 11:39



Da Sie Strings verwenden, wird das Wörterbuch wahrscheinlich schneller sein. Switch wird im Wesentlichen in eine Hashtabelle übersetzt, wenn Strings verwendet werden. Aber wenn Sie Ints oder ähnliches verwenden, wird es in eine Sprungtabelle übersetzt und wird schneller.

sehen diese Antwort und Frage für weitere Details

Am besten ist es, es zu profilieren und sicher zu finden


7
2017-08-26 11:58



Wie Sie den Wert jeder Eigenschaft erhalten, hat wahrscheinlich einen geringeren Einfluss auf die Gesamtleistung als das Rendering Ihres Gitters.

Lassen Sie mich Ihnen ein Beispiel geben: Nehmen wir an, Sie haben folgende Implementierung:

private string _latestFieldName = string.Empty;
private PropertyInfo _propertyInfo;

object GetFieldValue(string FieldName)
{
  if(FieldName != _latestFieldName)
  {
    _propertyInfo = typeof(yourTypeName).GetProperty(FieldName);
  }
  return _propertyInfo.GetValue(this,null);
}

Wenn Ihr Grid-Rendering eine Zeile nach der anderen durch Reflektion rendert, muss es die Eigenschaftsinfo jedes Mal abrufen. Wenn Sie Spalte für Spalte rendern, müssen Sie nur einmal die EigenschaftInfo für jede Eigenschaft abrufen, und da die Verzweigungsvorhersage immer dann korrekt ist, wenn Sie nur wenige Taktzyklen auf dem If verpassen würden. Wenn Sie PropertyInfo bereits haben und das Ergebnis des Aufrufs nicht in GetValue umwandeln müssen. Die Verwendung von Reflektion kommt dem Getter einer Eigenschaft sehr nahe, wenn es um Geschwindigkeit geht.

Mein Punkt ist, bevor Sie beginnen, einen Profiler zu optimieren. (Natürlich, wenn Sie das Gitter nicht gut ändern können, können Sie es auch nicht wirklich optimieren)


0
2017-08-26 16:50



Switch hat tatsächlich 2 Vorteile im Vergleich zum Wörterbuch:

  1. Sie können im Standardabschnitt eine benutzerdefinierte Ausnahmebedingungsnachricht erstellen, die einen ungültigen Wert enthalten kann. Im Falle eines Wörterbuchs erhalten Sie nur KeyNotFoundException, die keinen Schlüsselnamen enthält.
  2. Sie können mit Nullwerten umgehen. Das Wörterbuch kann null nicht als Schlüssel speichern.

0
2018-02-17 19:16