public class MyClass
{
public object Prop1 { get; set; }
public object Prop2 { get; set; }
public object Prop3 { get; set; }
}
Angenommen, ich habe ein Objekt myObject
von MyClass
und muss seine Eigenschaften zurücksetzen. Ist es besser, ein neues Objekt zu erstellen oder jede Eigenschaft neu zuzuweisen? Angenommen, ich habe keine zusätzliche Verwendung mit der alten Instanz.
myObject = new MyClass();
oder
myObject.Prop1 = null;
myObject.Prop2 = null;
myObject.Prop3 = null;
c#
object-oriented
construction
Glocken
quelle
quelle
Suppose I have an object myObject of MyClass and I need to reset its properties
- Wenn Sie die Eigenschaften Ihres Objekts zurücksetzen müssen oder die Problemdomäne modellieren möchten, erstellen Sie einereset()
Methode für MyClass. Siehe HarrisonPaines Antwort untenAntworten:
Das Instanziieren eines neuen Objekts ist immer besser, dann haben Sie 1 Stelle, um die Eigenschaften (den Konstruktor) zu initialisieren und können sie problemlos aktualisieren.
Stellen Sie sich vor, Sie fügen der Klasse eine neue Eigenschaft hinzu. Sie möchten lieber den Konstruktor aktualisieren, als eine neue Methode hinzuzufügen, mit der auch alle Eigenschaften neu initialisiert werden.
Es gibt Fälle, in denen Sie ein Objekt möglicherweise wiederverwenden möchten, in denen die Neuinitialisierung einer Eigenschaft sehr teuer ist und Sie sie behalten möchten. Dies wäre jedoch spezialisierter und Sie hätten spezielle Methoden, um alle anderen Eigenschaften neu zu initialisieren. Manchmal möchten Sie auch in dieser Situation noch ein neues Objekt erstellen.
quelle
myObject = new MyClass(oldObject);
. Dies würde jedoch eine exakte Kopie des ursprünglichen Objekts in einer neuen Instanz implizieren.new MyClass(oldObject)
ist die beste Lösung für die Fälle, in denen die Initialisierung teuer ist.Sie sollten es definitiv vorziehen, in den allermeisten Fällen ein neues Objekt zu erstellen . Probleme beim erneuten Zuweisen aller Eigenschaften:
A
und classB
also beide übergebene Instanzen von classC
sind, müssen sie wissen, ob sie jemals die gleiche Instanz erhalten werden und wenn ja, ob die andere Instanz sie noch verwendet. Dies verbindet eng Klassen, die sonst keinen Grund haben zu sein.Fraction
Klasse mit einem Zähler und einem Nenner und möchten erzwingen, dass sie immer reduziert wird (dh der GCD des Zählers und des Nenners ist 1). Dies ist unmöglich, wenn Sie zulassen möchten, dass Benutzer den Zähler und den Nenner öffentlich festlegen, da sie möglicherweise durch einen ungültigen Status wechseln, um von einem gültigen Status in einen anderen zu gelangen. ZB 1/2 (gültig) -> 2/2 (ungültig) -> 2/3 (gültig).Dies sind alles ziemlich bedeutende Probleme. Und was Sie als Gegenleistung für die zusätzliche Arbeit erhalten, die Sie erstellen, ist ... nichts. Das Erstellen von Instanzen von Objekten ist im Allgemeinen unglaublich kostengünstig, sodass der Leistungsvorteil fast immer vernachlässigbar ist.
Wie in der anderen Antwort bereits erwähnt, kann die Leistung nur dann relevant sein, wenn Ihre Klasse einige erheblich teure Arbeiten am Bau ausführt. Aber selbst in diesem Fall müssen Sie in der Lage sein, den teuren Teil von den Eigenschaften, die Sie zurücksetzen, zu trennen, damit diese Technik funktioniert. Daher können Sie stattdessen das Fliegengewichtmuster oder ähnliches verwenden.
Als Randnotiz, einige der oben genannten Probleme könnten etwas gemildert werden, indem keine Setter verwendet werden und stattdessen eine
public Reset
Methode für Ihre Klasse verwendet wird, die dieselben Parameter wie der Konstruktor verwendet. Wenn Sie aus irgendeinem Grund diesen Reset-Weg einschlagen möchten, wäre dies wahrscheinlich eine viel bessere Möglichkeit.Dennoch ist die zusätzliche Komplexität und Wiederholung, die hinzukommt, zusammen mit den oben genannten Punkten, die nicht angesprochen werden, immer noch ein sehr überzeugendes Argument dagegen, insbesondere wenn die nicht vorhandenen Vorteile gegeneinander abgewogen werden.
quelle
Angesichts des sehr allgemeinen Beispiels ist es schwer zu sagen. Wenn das Zurücksetzen der Eigenschaften im Fall der Domäne semantisch sinnvoll ist, ist es für den Konsumenten Ihrer Klasse sinnvoller, sie aufzurufen
Als
Ich würde NIEMALS verlangen, den Verbraucher Ihrer Klasse anzurufen
Wenn die Klasse etwas darstellt, das zurückgesetzt werden kann, sollte sie diese Funktionalität über eine
Reset()
Methode verfügbar machen, anstatt sich darauf zu verlassen, den Konstruktor aufzurufen oder seine Eigenschaften manuell festzulegen.quelle
Wie Harrison Paine und Brandin vorschlagen, würde ich dasselbe Objekt wiederverwenden und die Initialisierung der Eigenschaften in einer Reset-Methode faktorisieren:
quelle
Wenn das beabsichtigte Verwendungsmuster für eine Klasse ist, dass ein einzelner Besitzer einen Verweis auf jede Instanz speichert, werden in keinem anderen Code Kopien der Verweise gespeichert, und es kommt sehr häufig vor, dass Besitzer Schleifen haben, die mehrere Male ausgeführt werden müssen. " Füllen Sie "eine leere Instanz" aus, verwenden Sie sie vorübergehend und brauchen Sie sie nie wieder (eine gemeinsame Klasse, die ein solches Kriterium erfüllt, wäre das
StringBuilder
). Unter Performance-Gesichtspunkten kann es für die Klasse nützlich sein, eine Methode zum Zurücksetzen einer Instanz auf "Gefällt mir" einzuschließen. neue Bedingung. Eine solche Optimierung ist wahrscheinlich nicht viel wert, wenn für die Alternative nur einige hundert Instanzen erstellt werden müssten. Die Kosten für die Erstellung von Millionen oder Milliarden von Objektinstanzen können sich jedoch summieren.In einem verwandten Hinweis gibt es einige Muster, die für Methoden verwendet werden können, die Daten in einem Objekt zurückgeben müssen:
Methode erstellt neues Objekt; Gibt eine Referenz zurück.
Methode akzeptiert einen Verweis auf ein veränderbares Objekt und füllt es aus.
Methode akzeptiert eine Variable vom Referenztyp als
ref
Parameter und verwendet entweder das vorhandene Objekt, falls dies geeignet ist, oder ändert die Variable, um ein neues Objekt zu identifizieren.Der erste Ansatz ist oft semantisch der einfachste. Der zweite ist auf der anrufenden Seite etwas umständlich, bietet jedoch möglicherweise eine bessere Leistung, wenn ein Anrufer häufig ein Objekt erstellen und tausendfach verwenden kann. Der dritte Ansatz ist semantisch etwas umständlich, kann jedoch hilfreich sein, wenn eine Methode Daten in einem Array zurückgeben muss und der Aufrufer die erforderliche Arraygröße nicht kennt. Wenn der aufrufende Code den einzigen Verweis auf das Array enthält, entspricht das Umschreiben dieses Verweises mit einem Verweis auf ein größeres Array semantisch dem einfachen Vergrößern des Arrays (was semantisch das gewünschte Verhalten ist). Die Verwendung von
List<T>
Arrays ist in vielen Fällen unter Umständen besser als die Verwendung eines Arrays mit manueller Größenänderung. Arrays mit Strukturen bieten jedoch eine bessere Semantik und Leistung als Listen mit Strukturen.quelle
Ich denke, den meisten Menschen, die sich für die Erstellung eines neuen Objekts aussprechen, fehlt ein kritisches Szenario: die Garbage Collection (GC). GC kann in Anwendungen, in denen viele Objekte erstellt werden (z. B. Denkspiele oder wissenschaftliche Anwendungen), zu einem echten Leistungseinbruch führen.
Angenommen, ich habe einen Ausdrucksbaum, der einen mathematischen Ausdruck darstellt, wobei in den inneren Knoten Funktionsknoten (ADD, SUB, MUL, DIV) und die Blattknoten Endknoten (X, e, PI) sind. Wenn meine Knotenklasse eine Evaluate () -Methode hat, ruft sie wahrscheinlich rekursiv die untergeordneten Knoten auf und sammelt Daten über einen Datenknoten. Zumindest müssen alle Blattknoten ein Datenobjekt erstellen, und diese können dann auf dem Weg nach oben im Baum wiederverwendet werden, bis der endgültige Wert ausgewertet ist.
Angenommen, ich habe Tausende dieser Bäume und ich habe sie in einer Schleife ausgewertet. Alle diese Datenobjekte lösen einen GC aus und verursachen einen großen Leistungseinbruch (bis zu 40% CPU-Auslastungsverlust für einige Läufe in meiner App - ich habe einen Profiler ausgeführt, um die Daten abzurufen).
Eine mögliche Lösung? Verwenden Sie diese Datenobjekte erneut und rufen Sie sie einfach mit .Reset () auf, nachdem Sie sie verwendet haben. Die Blattknoten rufen nicht länger 'new Data ()' auf, sondern eine Factory-Methode, die den Lebenszyklus des Objekts abwickelt.
Ich weiß das, weil ich eine Anwendung habe, die dieses Problem behoben hat.
quelle