none
Objekte werden gleichzeitig im Original geändert RRS feed

  • Frage

  • Umgebung VS2022

    Hallo NG,

    ich kopiere vor dem Aufruf einer neuer neuen Form2 das Objekt, übergebe das Objekt dann an ein Property der Form2.
    Dort wird das Objekt geändert. Bei der Rückkehr möchte ich bei DialogResul.Cancel das Objekt aus der Sicherung wieder verwenden, aber das Original und das gesicherte Objekt sind ebenfalls verändert worden. Warum?

    Wer weis was da falsch läuft?

    Gruß Klaus

    Freitag, 27. Mai 2022 09:49

Antworten

  • Hallo Klaus,

    das ist normal. Du erstellst keine Kope, sondern einen Verweis. Eine Kopie kannst Du bspw. über eine Serialisierung/Deserialisierung erreichen. Das musst Du aber erst mal programmieren. Die bisherigen Clone/DeepClone Methoden in den Frameworks sind nicht wirklich sinnvoll verwendbar.

    Verweistypen werden nicht als Kopie, sondern nur als Verweis eingesetzt. D.h. eine Änderung an dem Objekt, egal, an welcher Stelle, "ändert" auch alle Referenzen (in den Referenzen wird natürlich nichts geändert, es sieht halt nur so aus, da Du ja immer nur das Originalobjekt siehst..

    Du müsstest also eine sog. deep copy des Objekts erstellen. Such mal bei Google nach Deep Copy C# oder Clone C#. Dann kommst du bspw. auf Artikel wie diesen hier:

      How to Clone Objects in C# .NET Core

    Ich für meinen Teil arbeite in der Regel mit Serialisierung/Deserialisierung für solche Aufgaben. Das ist in den meisten meiner Fälle die einfachste und effektivste Lösung.

    public class BinarySerializationUtilities
    {
    
        #region Binary Serialization helpers
    
        public static void SerializeObject<T>( string fileName, T data )
        {
            File.WriteAllBytes( fileName, SerializeObject<T>( data) );
        }
    
        public static byte[] SerializeObject<T>( T data )
        {
    
            byte[] result = null;
    
            BinaryFormatter serializer  = new BinaryFormatter();
            MemoryStream memoryStream = new MemoryStream();
    
            serializer.Serialize( memoryStream, data );
    
            result = memoryStream.GetBuffer();
    
            memoryStream.Close();
            memoryStream.Dispose();
    
            return result;
    
        }
    
        public static T DeserializeObject<T>( string fileName )
        {
            return DeserializeObject<T>( File.ReadAllBytes( fileName ) );
        }
    
        public static T DeserializeObject<T>( byte[] data )
        {
    
            T result = default(T);
    
            BinaryFormatter serializer = new BinaryFormatter();
            MemoryStream memoryStream = new MemoryStream( data.Length );
    
            result = (T)serializer.Deserialize( memoryStream );
    
            memoryStream.Close();
            memoryStream.Dispose();
    
            return result;
    
        }
    
        #endregion
    
    }

    Du kannst dir dann eine Methode DeepCopy, Clone, ... erstellen, die zuerst SerializeObject und auf deren Ergebnis dann DeserializeObject aufruft. Schon hast Du eine komplette Kopie erstellt.

    Hinweis: Beim BinarySerializer müssen alle zu verarbeitenden Klassen das Serializable Attribut haben. Bei manchen Klassen aus dem Framework bzw. auch von Drittanbietern ist das nicht der Fall. In dem Fall kann man bspw. auch JSON Serialisierung (ich nehme dann meist JSON.NET bzw. Newtonsoft.Json) einsetzen.

    P.S.: Es mag Fälle geben, in denen das Vorhaben mit jeglicher Art der Serialisierung nicht geht aber mir ist bei meinen Projekten noch kein solcher Fall untergekommen.


    Gruß, Stefan
    Microsoft MVP - Visual Developer ASP/ASP.NET (2001-2018)
    https://www.asp-solutions.de/ - IT Beratung, Softwareentwicklung, Remotesupport

    Freitag, 27. Mai 2022 13:47
    Moderator

Alle Antworten

  • Hallo Klaus,

    das ist normal. Du erstellst keine Kope, sondern einen Verweis. Eine Kopie kannst Du bspw. über eine Serialisierung/Deserialisierung erreichen. Das musst Du aber erst mal programmieren. Die bisherigen Clone/DeepClone Methoden in den Frameworks sind nicht wirklich sinnvoll verwendbar.

    Verweistypen werden nicht als Kopie, sondern nur als Verweis eingesetzt. D.h. eine Änderung an dem Objekt, egal, an welcher Stelle, "ändert" auch alle Referenzen (in den Referenzen wird natürlich nichts geändert, es sieht halt nur so aus, da Du ja immer nur das Originalobjekt siehst..

    Du müsstest also eine sog. deep copy des Objekts erstellen. Such mal bei Google nach Deep Copy C# oder Clone C#. Dann kommst du bspw. auf Artikel wie diesen hier:

      How to Clone Objects in C# .NET Core

    Ich für meinen Teil arbeite in der Regel mit Serialisierung/Deserialisierung für solche Aufgaben. Das ist in den meisten meiner Fälle die einfachste und effektivste Lösung.

    public class BinarySerializationUtilities
    {
    
        #region Binary Serialization helpers
    
        public static void SerializeObject<T>( string fileName, T data )
        {
            File.WriteAllBytes( fileName, SerializeObject<T>( data) );
        }
    
        public static byte[] SerializeObject<T>( T data )
        {
    
            byte[] result = null;
    
            BinaryFormatter serializer  = new BinaryFormatter();
            MemoryStream memoryStream = new MemoryStream();
    
            serializer.Serialize( memoryStream, data );
    
            result = memoryStream.GetBuffer();
    
            memoryStream.Close();
            memoryStream.Dispose();
    
            return result;
    
        }
    
        public static T DeserializeObject<T>( string fileName )
        {
            return DeserializeObject<T>( File.ReadAllBytes( fileName ) );
        }
    
        public static T DeserializeObject<T>( byte[] data )
        {
    
            T result = default(T);
    
            BinaryFormatter serializer = new BinaryFormatter();
            MemoryStream memoryStream = new MemoryStream( data.Length );
    
            result = (T)serializer.Deserialize( memoryStream );
    
            memoryStream.Close();
            memoryStream.Dispose();
    
            return result;
    
        }
    
        #endregion
    
    }

    Du kannst dir dann eine Methode DeepCopy, Clone, ... erstellen, die zuerst SerializeObject und auf deren Ergebnis dann DeserializeObject aufruft. Schon hast Du eine komplette Kopie erstellt.

    Hinweis: Beim BinarySerializer müssen alle zu verarbeitenden Klassen das Serializable Attribut haben. Bei manchen Klassen aus dem Framework bzw. auch von Drittanbietern ist das nicht der Fall. In dem Fall kann man bspw. auch JSON Serialisierung (ich nehme dann meist JSON.NET bzw. Newtonsoft.Json) einsetzen.

    P.S.: Es mag Fälle geben, in denen das Vorhaben mit jeglicher Art der Serialisierung nicht geht aber mir ist bei meinen Projekten noch kein solcher Fall untergekommen.


    Gruß, Stefan
    Microsoft MVP - Visual Developer ASP/ASP.NET (2001-2018)
    https://www.asp-solutions.de/ - IT Beratung, Softwareentwicklung, Remotesupport

    Freitag, 27. Mai 2022 13:47
    Moderator
  • Hallo Stefan,

    danke für die Antwort!

    Wofür gibt es denn eigentlich ref?

    Gruß KLaus

    Freitag, 27. Mai 2022 14:08
  • Hallo Klaus,

    vereinfacht gesagt ist ref meist für Wertetypen (int, double, ...) gedacht. Die werden normal immer als eigenes Objekt/eigene Instanz übergeben. Wenn man die also bspw. in einer Methode ändern will (siehe bspw. Int64.TryParse, ...) wird ref verwendet.

    Siehe dazu:

      ref (C#-Referenz)

    Es gibt zwar auch ref Anwendungsfälle mit Verweistypen, ich selbst hab davon aber noch nie Gebrauch machen müssen.


    Gruß, Stefan
    Microsoft MVP - Visual Developer ASP/ASP.NET (2001-2018)
    https://www.asp-solutions.de/ - IT Beratung, Softwareentwicklung, Remotesupport


    Freitag, 27. Mai 2022 14:13
    Moderator
  • Hallo Stefan,

    danke, war mir so nicht bewusst. Wundere mich nur dass ich nicht schon früher dieses Problem hatte.

    Gruß Klaus

    Freitag, 27. Mai 2022 14:26
  • Hallo Klaus,

    ich würde ja sagen "das war schon immer so" aber das hilft dir ja auch nicht :)

    Man lernt täglich neue Sachen (da nehm ich mich kein Stück aus, wär ja sonst auch langweilig :))


    Gruß, Stefan
    Microsoft MVP - Visual Developer ASP/ASP.NET (2001-2018)
    https://www.asp-solutions.de/ - IT Beratung, Softwareentwicklung, Remotesupport

    Freitag, 27. Mai 2022 14:36
    Moderator