In letzter Zeit habe ich es vorgezogen, 1-1-Beziehungen Dictionaries
anstelle von Switch
Anweisungen abzubilden . Ich finde es etwas schneller zu schreiben und mental einfacher zu verarbeiten. Leider möchte ich beim Zuordnen zu einer neuen Instanz eines Objekts dieses nicht so definieren:
var fooDict = new Dictionary<int, IBigObject>()
{
{ 0, new Foo() }, // Creates an instance of Foo
{ 1, new Bar() }, // Creates an instance of Bar
{ 2, new Baz() } // Creates an instance of Baz
}
var quux = fooDict[0]; // quux references Foo
Angesichts dieses Konstrukts habe ich CPU-Zyklen und Speicher verschwendet, indem ich 3 Objekte erstellt habe, wobei ich alles getan habe, was ihre Konstruktoren enthalten könnten, und nur eines davon verwendet habe. Ich glaube auch, dass das Zuordnen anderer Objekte fooDict[0]
in diesem Fall dazu führt, dass sie auf dasselbe verweisen, anstatt eine neue Instanz von Foo
wie beabsichtigt zu erstellen . Eine Lösung wäre, stattdessen ein Lambda zu verwenden:
var fooDict = new Dictionary<int, Func<IBigObject>>()
{
{ 0, () => new Foo() }, // Returns a new instance of Foo when invoked
{ 1, () => new Bar() }, // Ditto Bar
{ 2, () => new Baz() } // Ditto Baz
}
var quux = fooDict[0](); // equivalent to saying 'var quux = new Foo();'
Kommt das an einen Punkt, an dem es zu verwirrend ist? Es ist leicht, das ()
am Ende zu übersehen . Oder ist das Abbilden auf eine Funktion / einen Ausdruck eine ziemlich übliche Praxis? Die Alternative wäre, einen Schalter zu verwenden:
IBigObject quux;
switch(someInt)
{
case 0: quux = new Foo(); break;
case 1: quux = new Bar(); break;
case 2: quux = new Baz(); break;
}
Welcher Aufruf ist akzeptabler?
- Wörterbuch für schnellere Suche und weniger Stichwörter (case and break)
- Schalter: Wird häufiger im Code verwendet und erfordert nicht die Verwendung eines Func <> -Objekts zur Indirektion.
quelle
fooDict[0] is fooDict[0]
) dieselbe Instanz zurückgegeben . sowohl beim lambda als auch beim switch ist dies nicht der fallAntworten:
Das ist eine interessante Ansicht des Fabrikmusters . Ich mag die Kombination aus Dictionary und Lambda-Ausdruck. es hat mich dazu gebracht, diesen Behälter auf eine neue Art und Weise zu betrachten.
Ich ignoriere die Bedenken in Ihrer Frage zu CPU-Zyklen, wie Sie in den Kommentaren erwähnt haben, dass der Nicht-Lambda-Ansatz nicht das bietet, was Sie brauchen.
Ich denke, jeder Ansatz (Switch vs. Dictionary + Lambda) wird in Ordnung sein. Die einzige Einschränkung besteht darin, dass Sie mit dem Dictionary die Eingabetypen einschränken, die Sie zum Generieren der zurückgegebenen Klasse erhalten können.
Die Verwendung einer switch-Anweisung bietet Ihnen mehr Flexibilität bei den Eingabeparametern. Wenn dies jedoch ein Problem sein sollte, können Sie das Dictionary in eine Methode einschließen und das gleiche Endergebnis erzielen.
Wenn es für Ihr Team neu ist, kommentieren Sie den Code und erklären Sie, was los ist. Fordern Sie eine Team-Code-Überprüfung an, führen Sie sie durch das, was getan wurde, und machen Sie sie darauf aufmerksam. Davon abgesehen sieht es gut aus.
quelle
case 0: quux = new Foo(); break;
wirdcase 0: return new Foo();
dies natürlich genauso einfach zu schreiben und viel einfacher zu lesen als{ 0, () => new Foo() }
C # 4.0 gibt Ihnen die
Lazy<T>
Klasse, die Ihrer eigenen zweiten Lösung ähnelt, aber "Lazy initialization" expliziter ausruft.quelle
Stilistisch denke ich, dass die Lesbarkeit zwischen ihnen gleich ist. Es ist einfacher, Abhängigkeitsinjektionen mit der zu erstellen
Dictionary
.Vergessen Sie nicht, dass Sie überprüfen müssen, ob der Schlüssel vorhanden ist, wenn Sie den verwenden
Dictionary
, und einen Fallback bereitstellen müssen, wenn dies nicht der Fall ist.Ich würde die
switch
Anweisung für statische Codepfade undDictionary
für dynamische Codepfade (wo Sie Einträge hinzufügen oder entfernen können) bevorzugen . Der Compiler ist möglicherweise in der Lage, einige statische Optimierungen mit dem auszuführenswitch
, die er mit dem nicht ausführen kannDictionary
.Interessanterweise ist dieses
Dictionary
Muster das, was Leute manchmal in Python tun, weil Python dieswitch
Anweisung fehlt . Ansonsten verwenden sie If-else-Ketten.quelle
Im Allgemeinen würde ich auch nicht bevorzugen.
Was auch immer dies verbraucht, sollte mit einem funktionieren
Func<int, IBigObject>
. Die Quelle Ihres Mappings kann dann ein Dictionary oder eine Methode sein, die eine switch-Anweisung oder einen Web-Service-Aufruf oder eine Dateisuche hat ... wie auch immer.Was die Implementierung angeht, würde ich das Wörterbuch vorziehen, da dies einfacher überarbeitet werden kann: "Hardcode-Wörterbuch, Suchschlüssel, Rückgabeergebnis" bis "Wörterbuch aus Datei laden, Suchschlüssel, Rückgabeergebnis".
quelle