none
Ein Object kopieren - Meine Art scheint nicht zu gehen - Alternativen oder Lösungen RRS feed

  • Frage

  • Hallo liebe Programmier-Kollegen da draußen.

    Ich habe ein kleines Problem was mich schon länger stört. Wenn ich ein Object als eine Kopie benötige, bevor ich es endgültig übernehme, kenne ich nur die Möglichkeit der normalen Zuweisung: 

    MyClass copy = original;

    Doch ist copy ja dann exakt das selbe Object und wenn ich dort Änderungen vornehme, dann werden die in original auch übernommen.

    Dann gibt es ja noch die Möglichkeit, einfach alle Werte zu übernehmen:

    MyClass copy = new MyClass()
    {
      wert1 = original.wert1,
      wert2 = original.wert2
      //...
    };

    Doch fand ich das zu kompliziert auf dauer. Vor allem weil man jeden neuen Wert überall ergänzen müsste.

    __

    Ich dachte mir also eine Methode zu schreiben. Diese arbeitet zwar mit Reflection, sollte aber für meine Anwendungen kein Nachteil sein.

    public static T CopyObject<T> ( T original ) where T : new ()
    {
      T toReturn = new T ();
    
      foreach ( PropertyInfo info info original.GetType().GetProperties () )
      {
        toReturn.GetType ().GetProperty ( info.Name ).SetValue ( info.GetValue ( original ), toReturn );
      }
    
      return toReturn;
    }


    So sieht das ganze aus. Doch kommt nun ein Fehler im foreach-Block: 

    Ein Ausnahmefehler des Typs "System.Reflection.TargetException" ist in mscorlib.dll aufgetreten.
    
    Zusätzliche Informationen: Das Objekt stimmt mit dem Zieltyp nicht überein.

    Es ist bestimmt ein simpler kleiner Fehler, doch finde ich ihn nach langem suchen nicht.

    Es wäre toll wenn einer von euch mir die Lösung für dieses Problem liefern könnte, oder mir eine Alternative bieten kann.

    Dank euch jetzt schon mal.

    lg


    Samstag, 24. Oktober 2015 17:54

Antworten

Alle Antworten

  • Hallo,

    man muss die Parameter von SetValue schon in der richtigen Reihenfolge übergeben:

    toReturn.GetType ().GetProperty ( info.Name ).SetValue (toReturn, info.GetValue ( original ));


    Tom Lambert - .NET (C#) MVP
    Wozu Antworten markieren und für Beiträge abstimmen? Klicke hier.
    Nützliche Links: .NET Quellcode | C# ↔ VB.NET Konverter | Account bestätigen (Verify Your Account)
    Ich: Webseite | Code Beispiele | Facebook | Twitter | Snippets

    Samstag, 24. Oktober 2015 18:27
    Moderator
  • Hi,

    abgesehen davon, dass dein Code in komplexeren Klassen mit untergeordneten Objekten so nicht funktioniert (da dann für Eigenschaften, die selbst Objekte beinhalten, trotzdem nur ein Verweis erstellt wird) würde ich es mal mit binärer Serialisierung/Deserialisierung probieren. Das sollte besser klappen und auch die gesamte Hierarchie berücksichtigen.

    Geht natürlich nur, wenn alle Klassen, die in der Struktur vorhanden sind, auch serialisierbar sind, in der Regel klappt das aber ganz gut.

    Public Shared Function SerializeObjectBinary( ByVal DataObject As Object ) As Byte()
    
    Dim Result       As Byte()
    Dim Serializer   As New BinaryFormatter()
    Dim MemoryStream As New MemoryStream()
    
        Serializer.Serialize( MemoryStream, DataObject )
    
        Result = MemoryStream.GetBuffer()
    
        MemoryStream.Close()
        MemoryStream.Dispose()
    
        Return Result
    
    End Function
    
    Public Shared Function DeserializeObjectBinary( Of T )( ByVal Content As Byte() ) As T
    
    Dim Result       As T
    Dim Serializer   As New BinaryFormatter()
    Dim MemoryStream As New MemoryStream( Content.Length )
    
        Result = DirectCast( Serializer.Deserialize( MemoryStream ), T )
    
        MemoryStream.Close()
        MemoryStream.Dispose()
    
        Return Result
    
    End Function

    Der Code ist zwar jetzt in VB.NET, das sollte aber problemlos für dich umstellbar sein. Falls nicht, meld dich nochmal dazu.

    Performancetechnisch ist das für einzelne Verwendung problemlos. Bei massenhafter Verarbeitung wäre eine Alternative ggfs. sinnvoller (aber auch komplizierter).

      http://www.codeproject.com/Articles/151946/A-High-Performance-Binary-Serializer-using-Microso

    Alternativ kannst Du natürlich auch eine Rekursion in deinen Code einbauen, der dann auch die Hierarchie berücksichtigt.

    Zum Fehler selbst. Steht da wirklich

    foreach ( PropertyInfo info info original.GetType().GetProperties () )

    in deinem Code? Falls ja, sollte der eigentlich gar nicht laufen, da das zweite "info" wohl eher ein "in" sein sollte, oder?

    Die zweite Zeile:

    toReturn.GetType ().GetProperty ( info.Name ).SetValue ( info.GetValue ( original ), toReturn );

    ist dann auch falsch, probier mal:

    toReturn.GetType().GetProperty( info.Name ).SetValue( toReturn, info.GetValue( original ), null );

    Unter Umständen wäre es auch sinnvoll, solche Zeilen in mehrere zu splitten, das erhöht die Übersichtlichkeit evtl. ein wenig.



    Gruß, Stefan
    Microsoft MVP - Visual Developer ASP/ASP.NET
    http://www.asp-solutions.de/ - Consulting, Development
    http://www.aspnetzone.de/ - ASP.NET Zone, die ASP.NET Community

    Samstag, 24. Oktober 2015 18:35
    Moderator
  • Hallo,

    man muss die Parameter von SetValue schon in der richtigen Reihenfolge übergeben:

    toReturn.GetType ().GetProperty ( info.Name ).SetValue (toReturn, info.GetValue ( original ));


    Tom Lambert - .NET (C#) MVP
    Wozu Antworten markieren und für Beiträge abstimmen? Klicke hier.
    Nützliche Links: .NET Quellcode | C# ↔ VB.NET Konverter | Account bestätigen (Verify Your Account)
    Ich: Webseite | Code Beispiele | Facebook | Twitter | Snippets

    Ehm ja. Ich danke dir. Wie ich das übersehen konnte ist mir ein Rätsel. :P

    lg

    Samstag, 24. Oktober 2015 18:48