2010-07-17 7 views

Antwort

5

Pavel Minaev's answer from another discussion:

Andere haben bereits erklärt, über MemberwiseClone, aber niemand gab die Erklärung, warum es geschützt ist. Ich werde versuchen, die Begründung zu geben.

Das Problem hier ist, dass MemberwiseClone nur blind den Zustand kopiert. In vielen Fällen ist dies unerwünscht. Zum Beispiel könnte das Objekt ein privates Feld haben, das ein Verweis auf eine Liste ist. Eine flache Kopie, wie sie MemberwiseClone ausführt, würde dazu führen, dass ein neues Objekt auf dieselbe Liste verweist - und die Klasse könnte durchaus geschrieben sein, dass sie nicht erwartet, dass die Liste mit anderen geteilt wird.

Oder ein Objekt kann eine Art ID-Feld haben, generiert im Konstruktor - wieder, wenn Sie das Klonen, erhalten Sie zwei Objekte mit der gleichen ID, die zu allen Arten von seltsamen Fehlern in Methoden unter der Annahme, dass ID ist einzigartig.

Oder Sie haben ein Objekt, das einen Socket oder einen Dateistream öffnet und einen Verweis darauf speichert. MemberwiseClone kopiert einfach die Referenz - und Sie können sich vorstellen, dass zwei Objekte, die versuchen, Aufrufe an denselben Stream zu verschachteln, nicht gut enden werden.

Kurz gesagt, "Klonen" ist keine wohldefinierte Operation für beliebige Objekte. Die Tatsache, dass memberwise operator = standardmäßig für alle Klassen in C++ vorgesehen ist, ist eher lästig, da die Leute zu oft vergessen, dass sie da ist, und sie nicht für Klassen deaktiviert, für die Kopieren nicht sinnvoll oder gefährlich ist (und es gibt überraschend viele solcher Klassen).

1

Wenn MemberwiseClone nicht existiert, gibt es keine andere Möglichkeit, als Reflection für eine vererbbare Klasse zu verwenden, die eine polymorphe Klonoperation unterstützt, außer dass jede abgeleitete Klasse explizit eine angeben muss. Wenn eine abgeleitete Klasse keine Klonoperation bereitstellt, führt dies zu einem unerwarteten Verhalten. Angenommen, Fahrzeug, Auto und ToyotaCar bieten explizite Klonierungsmethoden, ToyotaCorolla jedoch nicht. Hat jemand ein Objekt vom Typ ToyotaCorolla und versucht es zu klonen, wäre das Ergebnis ein ToyotaCar. Da es Situationen gibt, in denen polymorphes Klonen erforderlich ist und es unbequem wäre, jede abgeleitete Klasse einer klonbaren Klasse explizit zu unterstützen, ist MemberwiseClone ein notwendiger Bestandteil des Frameworks.

Auf der anderen Seite kann MemberwiseClone auch gefährlich sein. Das Ausführen eines MemberwiseClone für ein Objekt führt häufig zu einem beschädigten Objekt. Der Versuch, beliebige Eigenschaften oder Methoden des defekten Objekts zu verwenden, kann das Original beschädigen.

Es ist schade, dass Microsoft eine gute Praxis für das Klonen nicht besser definiert hat. Es ist möglich und nicht allzu schwierig, ein polymorphes Klonierungsmuster zu entwerfen, das keine geerbten Klassen benötigt, um explizit etwas zu tun, es sei denn, sie fügen Felder hinzu, die eine spezielle Behandlung erfordern, oder wenn ein Aufrufer den deklarierten Rückgabetyp der Klonmethode erwartet die abgeleitete Klasse. Während die letztere Situation häufig eine Voraussetzung ist, führt ein Fehler bei der expliziten Implementierung der erforderlichen Methode zu einem Kompilierungsfehler und nicht zu fehlerhaftem Laufzeitverhalten.

BTW, Microsoft scheint zu glauben, dass etwas über tiefe Klonen kloniert. Es ist nicht. Der Aufruf von "Clone" für ein Objekt sollte das Objekt in die Tiefe klonen, die notwendig ist, um seine definierte Semantik zu erhalten. Das Klonen eines FileCabinet (Of T) sollte ein neues FileCabinet ergeben, das für die Methoden von FileCabinet unabhängig vom Original ist, aber es sollte die gleichen T-Instanzen enthalten wie das Original.Da der Zweck eines Archivs darin besteht, Instanzen von T zu halten, aber nichts damit zu tun, sollte das Klonen des Gehäuses nicht bedeuten, den Inhalt zu klonen (aber es würde das Klonen irgendwelcher Arrays bedeuten, die der Schrank selbst verwendet, um den Inhalt zu halten).

Übrigens, wenn ich meine druthers hätte, würde es eine Schnittstelle in .Net geben, die durch String und primitive Typen (plus viele andere), genannt DeepClonableIfMutable, implementiert wird. Bei Anwendung auf einen String oder ein anderes Grundelement würde die DeepCloneIfMutable-Methode einfach das ursprüngliche Objekt zurückgeben. Benutzerdefinierte unveränderbare Objekte könnten DeepClonableIfMuguable implementieren, um sich ähnlich zu verhalten, während veränderbare Objekte sich selbst und alle verschachtelten DeepClonableIfMutable-Instanzen tiefklonen.

2
  • Eine Menge Dinge machen keinen Sinn zu klonen; alles, was
  • Die meisten Objekte auf einem nicht verwalteten Griff, zum Beispiel spricht richtig ist wirklich schwer, wenn Sie außerhalb von ein paar einfachen Fällen gehen
  • nicht brauchen
  • Tief Kopieren etwas ein Klon-Anlage in vielen Fällen gibt es bessere Metaphern als blinde Klone
  • manuell Klon Anlage auf Ihre Typen hinzufügen, die es brauchen trivial einfach ist

Für mich dann, es ist ein Kinderspiel, dass dies nicht der öffentlichen API standardmäßig hinzugefügt werden soll.

Verwandte Themen