Meine zwei Cent für Deep Copy vs Shallow Copy in .Net

Microsoft .Net bietet Unterstützung für das Klonen von Objekten - eine Möglichkeit, eine exakte Kopie eines Objekts (auch als Klon bezeichnet) zu erstellen. Es gibt zwei Arten des Klonens: flache und tiefe Kopien. Während Ersteres durch Aufrufen der MemberwiseClone-Methode der System.Object-Klasse implementiert werden kann, ist die Implementierung von Letzterem etwas schwierig, da Sie im Framework standardmäßig keine Unterstützung dafür haben. Während eine flache Kopie die Referenzen ohne die referenzierten Objekte kopiert, erstellt ein tiefer Klon im Wesentlichen eine Kopie des Quellobjekts zusammen mit seinen Referenzen.

Welche Optionen stehen zum Klonen zur Verfügung?

Um eine Instanz einer Klasse in C # zu klonen, haben Sie einige Optionen zur Auswahl. Dazu gehören die folgenden:

  • Verwenden der System.Object.MemberwiseClone-Methode zum Durchführen einer flachen Kopie
  • Verwenden von Reflection unter Verwendung der Activator.CreateInstance-Methode
  • Serialisierung verwenden
  • Durch die Implementierung der IClonable-Schnittstelle

Beachten Sie, dass Sie beim Klonen von Objekten oder Instanzen von Klassen in .Net keine statischen Elemente oder statischen Felder berücksichtigen müssen. Der Grund dafür ist, dass statische Objekte an einem gemeinsam genutzten Speicherort gespeichert werden und Ihnen pro Anwendungsdomäne ein Speicherort zugewiesen ist.

Flache Kopie vs. tiefe Kopie

Stellen Sie sich eine Klasse Employee vor und erstellen Sie eine Instanz der Employee-Klasse wie unten gezeigt.

Employee emp = new Employee();

Employee clone = emp;

Siehe den obigen Code-Ausschnitt. Der Zuweisungsoperator "=" würde die Referenz und nicht das eigentliche Objekt kopieren. Die in der System.Object-Klasse definierte MemberwiseClone () -Methode macht genau dasselbe. Dies sind Beispiele für flache Kopien. Wenn Sie also einen Zuweisungsoperator zum Kopieren und Objektieren in ein anderes verwenden oder die Memberwise.Clone () -Methode verwenden, erstellen Sie tatsächlich eine flache Kopie des Objekts.

Während in einer flachen Kopie die Elemente des kopierten Objekts auf dasselbe Objekt wie das ursprüngliche Objekt verweisen, werden in einer tiefen Kopie separate Instanzen jedes Referenztypmitglieds in der ursprünglichen Instanz in der neuen oder geklonten Instanz erstellt. Wenn Sie also einen Referenztyp in der ursprünglichen Instanz haben, enthält die neue Instanz auch dasselbe Referenztypelement, aber dieser Referenztyp verweist auf eine insgesamt neue Instanz.

Beim flachen Kopieren wird ein neues Objekt erstellt und dann werden die nicht statischen Elemente des Quellobjekts in das Zielobjekt oder das neue Objekt kopiert. Wenn das Element ein Feld vom Werttyp ist, wird eine bitweise Kopie des Feldes durchgeführt. Wenn das zu kopierende Element ein Referenztyp ist, wird die Referenz dagegen kopiert. Daher beziehen sich das Referenzelement innerhalb des ursprünglichen Objekts und die Zielobjekte auf dasselbe Objekt im Speicher.

Wenn Sie eine Sammlung mit einzelnen Elementen haben und eine flache Kopie der Sammlungsinstanz ausführen möchten. Es ist zu beachten, dass eine flache Kopie einer Sammlungsinstanz die Struktur der Sammlung kopiert, nicht jedoch die Elemente in der Sammlung. Nachdem Sie eine flache Kopie der Sammlungsinstanz erstellt haben, haben Sie zwei Sammlungen, die die einzelnen Elemente der Sammlung gemeinsam nutzen. Im Gegenteil, wenn Sie eine tiefe Kopie der Sammlungsinstanz ausführen, werden zwei Sammlungsinstanzen mit den einzelnen Elementen der ursprünglichen Sammlung dupliziert.

Implementieren von Deep Copy mithilfe der Serialisierung

Sie können Deep Copy auf viele Arten implementieren. Eine der am meisten bevorzugten Möglichkeiten zum Implementieren einer tiefen Kopie eines Objekts ist die Verwendung der Serialisierung. Sie können die Reflexion auch nutzen, um eine tiefe Kopie einer Instanz einer Klasse zu erstellen. Das folgende Codefragment zeigt, wie Sie eine Methode schreiben können, die die binäre Serialisierung implementiert, um eine tiefe Kopie einer Instanz mit C # durchzuführen.

public static T DeepCopy(T obj)

       {

           if (!typeof(T).IsSerializable)

           {

               throw new Exception("The source object must be serializable");

           }

           if (Object.ReferenceEquals(obj, null))

           {

               throw new Exception("The source object must not be null");

           }

           T result = default(T);

           using (var memoryStream = new MemoryStream())

           {

                var formatter = new BinaryFormatter();

               formatter.Serialize(memoryStream, obj);

               memoryStream.Seek(0, SeekOrigin.Begin);

               result = (T)formatter.Deserialize(memoryStream);

               memoryStream.Close();

           }

           return result;

       }

In Anbetracht der Tatsache, dass Sie eine Entitätsklasse namens Employee haben, können Sie eine tiefe Kopie einer Instanz der Employee-Klasse ausführen, wie im folgenden Codeausschnitt gezeigt.

static void Main(string[] args)

       {

           Employee emp = new Employee();

           emp.EmployeeId = 1;

           emp.FirstName = "Joydip";

           emp.LastName = "Kanjilal";

           Employee clone = DeepCopy(emp);

           if(Object.ReferenceEquals(emp, clone))

           {

               Console.WriteLine("References are the same.");

           }

           else

           {

               Console.WriteLine("References are different.");

           }

       }

Wenn Sie das obige Programm ausführen, wird eine tiefe Kopie der Instanz "emp" ausgeführt und die Meldung "Referenzen sind unterschiedlich". wird Angezeigt werden.