abstract + ICloneable Clone



  • -.- Nich dein Ernst oder?

    Type t = this.GetType();
    

    Aber wie gesagt, setz es so um wie es theta schon gesagt hat. Indem du die Clone Methode in den Abgeleiteten Klassen implementierst.



  • theta schrieb:

    Also wenn Du deinem zu klonenden Objekt eh schon this übergibst, dann kannst Du gleich die Clone() Methoden nur in den abgeleiteten Klassen impl.

    Das werde ich wahrscheinlich machen das es am einfachsten für mich ist, obwohl bei 30 verschiedenen Devicetypen würde es nicht so lustig sein.

    Das mit dem serialisieren verstehe ich leider nicht.-> Heist das einfach nur dass ich es in ein File schreiben soll und dann wieder rauslesen soll und in ein neues Objekt schreiben soll?

    theta schrieb:

    Oder Du setzt die Klasse Acttivator ein:
    Bsp:

    T item = (T)Activator.CreateInstance(typeof(T), new object[] { ... });
    

    Schreibe ich dass in die Clone Methode der Abstrakten Klasse??
    Wenn ja was muss ich dann für T schreiben in meinem konkreten Beispiel?? Das Problem ist ja, dass ich T nicht kenne.



  • Firefighter schrieb:

    -.- Nich dein Ernst oder?

    Type t = this.GetType();
    

    Das zwar nicht 😃
    Aber was mache ich nun mit diesem t?
    kann ja schlecht

    public virtual object Clone()
    {
    
     Type t = this.GetType();
     t gg = new t();
     return gg;
    }
    

    schreiben.
    Was soll ich mit dem t weitermachen?

    Firefighter schrieb:

    Aber wie gesagt, setz es so um wie es theta schon gesagt hat. Indem du die Clone Methode in den Abgeleiteten Klassen implementierst.

    Also so????

    abstract class Device
    {
    .
    .
    
    }
    
    class Device1: Device, ICloneable
    {
     public object Clone()
     {
      ...
     }
    
    }
    
    class Device2: Device, ICloneable
    {
    .
    .
     public object Clone()
     {
      ...
     }
    }
    


  • THE_ONE schrieb:

    theta schrieb:

    Also wenn Du deinem zu klonenden Objekt eh schon this übergibst, dann kannst Du gleich die Clone() Methoden nur in den abgeleiteten Klassen impl.

    Das werde ich wahrscheinlich machen das es am einfachsten für mich ist, obwohl bei 30 verschiedenen Devicetypen würde es nicht so lustig sein.

    Das mit dem serialisieren verstehe ich leider nicht.-> Heist das einfach nur dass ich es in ein File schreiben soll und dann wieder rauslesen soll und in ein neues Objekt schreiben soll?

    theta schrieb:

    Oder Du setzt die Klasse Acttivator ein:
    Bsp:

    T item = (T)Activator.CreateInstance(typeof(T), new object[] { ... });
    

    Schreibe ich dass in die Clone Methode der Abstrakten Klasse??
    Wenn ja was muss ich dann für T schreiben in meinem konkreten Beispiel?? Das Problem ist ja, dass ich T nicht kenne.

    Das schreibst Du in die abstrakte Klasse.
    Du musst einen Type übergeben und ich habe in meinem Bsp einfach typeof(T) genommen, Du nimmst this.GetType()...
    Simon



  • theta schrieb:

    Du musst einen Type übergeben und ich habe in meinem Bsp einfach typeof(T) genommen, Du nimmst this.GetType()...
    Simon

    Das war mir klar dass ich statt typeof(T) einfach this.GetType() nehmen muss. Leider ist mir nicht klar was ich statt dem T item schreiben soll, ich kenne das T ja nicht?

    T item = (T)(Activator.CreateInstance(this.GetType()));
    

    Das einzige was ich bis jetzt ohne Fehler zum laufen bekommen habe (also kein PSEUDO Code) ist das:

    public override object Clone()
    {
     object newInstance = Activator.CreateInstance(this.GetType());
     return newInstance;
    }
    

    Nur leider ist newInstance leider nicht vom Type this.GetType() sondern vom Type object.



  • Um wat geht es denn bei deiner Clone Methode überhaupt?Soll sie ein neues Element eines Device zurückgeben oder wie?Dann mach das doch einfach so

    public object Clone()
    {
     Device newInstance = Activator.CreateInstance(this.GetType());
     return newInstance;
    }
    

    Oder hab ich das falsch verstanden?



  • Firefighter schrieb:

    Um wat geht es denn bei deiner Clone Methode überhaupt?Soll sie ein neues Element eines Device zurückgeben oder wie?Dann mach das doch einfach so

    public object Clone()
    {
     Device newInstance = Activator.CreateInstance(this.GetType());
     return newInstance;
    }
    

    Oder hab ich das falsch verstanden?

    Nein du hast das richtig verstanden.
    Genau das hatte ich schon selbst probiert gehabt.
    Leider mit dem Fehler

    Fehler	1	Der Typ "object" kann nicht implizit in "SimulationSetup.Device" konvertiert werden. 
    Es ist bereits eine explizite Konvertierung vorhanden. (Möglicherweise fehlt eine Umwandlung.)	
    C:\csharp\SimulationSetup\SimulationSetup\Device.cs	139	34	SimulationSetup
    


  • In der Compilerfehlermeldung steht doch schon alles:

    Möglicherweise fehlt eine Umwandlung.

    !!!



  • also das Clone soll mir je nach Ausgangsobject (Device1 oder Device2) ein Device1 oder Device2 zurückliefern mit dem Inhalt das Ausgangsobjects.

    Also genau das was man sich von einem Clone erwarte. Ein komplett identisches Replikat des anderen.
    So wie bei dem Schaf Dolly. Nach dem clonen waren da 2 identische Schafe. Nicht nur dass es ein Tier (Device) war sondern es war wieder ein Schaf mit exakt den gleichen Merkmalen wie das Ausgangsschaf (eine exakte Kopie vom Ausgangsschaf )(z.B.: Instanz von Device1 - alle Variablen der Instanzen haben den gleichen Inhalt).

    Ich will also nicht nur eine Clone Funktion für ein bestimmtes Tier (Schaf - z.B Device1) sondern eine Clone Funktion für alle Tiere (Device).



  • Das Problem ist zu definieren was mit "genau identisch" gemeint ist. Willst du eine flache oder eine tiefe Kopie?



  • O.o schrieb:

    Das Problem ist zu definieren was mit "genau identisch" gemeint ist. Willst du eine flache oder eine tiefe Kopie?

    meine Classendefinition:

    abstract class Device : ICloneable
    {
            private static long idcounter = 0;
    
            protected Point position;
            protected Point midpoint;
            protected Bitmap symbol;
            protected int type;
            protected bool selected;
            protected long id;
            protected long connectedWith;
    

    Alle diese Werte sollen gleich sein, also würde ich tief sagen.
    da von position,midpoint und symbol neue Instanzen angelegt werden müssen, obwohl mit gleichem Inhalt.



  • Du hast nicht verstanden worauf ich hinaus will.

    Willst du, dass nach dem klonen jedes Schaf seine eigenen Eingeweide hat (tiefe Kopie) oder willst du, dass sie sich die Eingeweide teilen, siamesische Zwillinge sozusagen (flache Kopie).

    Du musst dir im Klaren sein, wenn du eine tiefe Kopie willst, dass das je nach Komplexität des zu klonenden Objekts ziemlich ausarten kann.

    Das Problem an einer flachen Kopie ist aber, dass wenn du im einen Objekt, z.B. die Einträge einer Liste veränderst, diese sich im anderen Objekt genauso ändert (es werden nur die Referenzen kopiert, nicht die Objekte selbst).



  • Ich will Clonen und nicht Frankenstein spielen.
    Also jedes Schaf hat seine eigenen Eingeweide.
    Also tiefe Kopie.



  • Dann weißt du ja was zu zu tun hast.

    Value-types kannst du ohne Bedenken so kopieren.
    Reference-types musst du entweder über ICloneable.Clone klonen oder sie "von Hand" kopieren.

    abstract class Device : ICloneable
    {
      public object Clone()
      {
        Device clone = new Device();
        clone.position = this.position;
        clone.symbol = this.position.Clone();
        // usw. usf.
      }
    }
    


  • O.o schrieb:

    Dann weißt du ja was zu zu tun hast.

    Nein weiß ich nicht!

    Weil 1stens dein Code nicht funktioniert da die Klasse abstract ist und nicht instanziert werden kann.
    Bekomme:

    Fehler	1	Es konnte keine Instanz der abstrakten Klasse oder Schnittstelle "SimulationSetup.Device" erstellt werden.	C:\csharp\SimulationSetup\SimulationSetup\Device.cs	140	28	SimulationSetup
    

    O.o schrieb:

    abstract class Device : ICloneable
    {
      public object Clone()
      {
        Device clone = new Device();
        clone.position = this.position;
        clone.symbol = this.position.Clone();
        // usw. usf.
      }
    }
    

    Und 2tens haben nicht alle Elemente eine Clone Funktion. Daher ist sowas (Copy Constructor) angebracht wenn es keine Clone Funktion gibt:

    public object Clone()
            {
                //we create a new instance of this specific type.            
                //object newInstance = Activator.CreateInstance(this.GetType());
                Device clone = new Device();
                clone.position = new Point(this.position);
                clone.symbol = new Bitmap(this.symbol);
                .
                .
                .
                return clone;
            }
    

    Aber wie gesagt funktioniert der Code ja noch immer nicht da ich kein object erzeugen kann. Habe also noch immer das Problem dass ich von Anfang an hatte. 😞

    Um Flache bzw tiefe Kopie mache ich mir keine Sorgen. Ich muss nur endlich mal wissen wie man eine neue Instanz eines Types erstellt von dem man den type nicht explizit kennt.



  • Also Du musst dich für eine Variante entscheiden.
    z.B. die folgende (wurde ganz am Anfang mal vorgeschlagen):

    public abstract class Device : ICloneable
    {
       // ...
    }
    
    public class Device1 : Device
    {
       private int v = 27;
    
       public object Clone()
       {
          Device1 d = new Device1();
          d.v = v;
          return d;
       }
    }
    
    public class Device2 : Device
    {
       private char a = 255;
    
       public object Clone()
       {
          Device2 d = new Device2();
          d.a = a;
          return d;
       }
    }
    


  • Danke theta für deine Hilfe! Das hatte ich heute schon mal implementiert gehabt,leider funktioniert das nicht. Bekomme den Fehler:

    SimulationSetup.Device implementiert den Schnittstellenmember "System.ICloneable.Clone()" nicht.
    


  • public abstract class Device : ICloneable
        {
            // ...
            #region ICloneable Member
    
            abstract public object Clone();
    
            #endregion
        }
    
        public class Device1 : Device
        {
            private int v = 27;
    
            public override object Clone()
            {
                Device1 d = new Device1();
                d.v = v;
                return d;
            }
        }
    
        public class Device2 : Device
        {
            private byte a = 255;
    
            public override object Clone()
            {
                Device2 d = new Device2();
                d.a = a;
                return d;
            }
        }
    


  • Herzlichsten Dank Knuddlbaer, dein Code funktioniert! 👍
    Hab für das bessere Verständnis ein kleines Testprogramm geschrieben.

    //Animal.cs
    using System;
    using System.Collections.Generic;
    using System.Text;
    
    namespace AnimalTest
    {
        public abstract class Animal :ICloneable
        {
            public abstract int geta();
            #region ICloneable Member
    
            abstract public object Clone();
    
            #endregion 
        }
    
        public class Pig : Animal
        {
            public int a = 10;
    
            public Pig()
            {
                this.a = 30;
            }
    
            public override object Clone() 
            {
                Pig d = new Pig();
                return d;
            }
            public override int  geta()
            {
     	        return a;
            }
        }
    
        public class Cow : Animal
        {
            public int a = 0;
    
            public Cow()
            {
                this.a = 20;
            }
    
            public override object Clone() 
            {
                Cow d = new Cow();
                return d;
            }
            public override int  geta()
            {
     	        return a;
            }
        }
    }
    

    zum testen habe ich eine Form mit zwei Buttons und einem Label erstellt.
    der Code dazu ist folgender:

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Text;
    using System.Windows.Forms;
    
    namespace AnimalTest
    {
        public partial class Form1 : Form
        {
            List<Animal> liste;
    
            public Form1()
            {
                InitializeComponent();
                liste = new List<Animal>();
                liste.Add(new Cow());
                liste.Add(new Pig());
            }
    
            private void button1_Click(object sender, EventArgs e)
            {
                Animal f = (Animal) liste[0].Clone();
                this.label1.Text = f.geta().ToString();
            }
    
            private void button2_Click(object sender, EventArgs e)
            {
                Animal f = (Animal)liste[1].Clone();
                this.label1.Text = f.geta().ToString();
            }
        }
    }
    

    Wie man sieht ist die Clonefunktion bei beiden Tierarten gleich. Daher war meine anfänglich Überlegung die Funktion nur einmal zu definieren. Bei zwei Tierarten ist es ja nicht tragisch die Clonefunktion zu überschreiben. Nur bei 40 oder noch mehr Tierarten ist es nicht mehr so lustig. Daher ist und bleibt meine Frage kann man das clonen in die abstracte Klasse verschieben, sodass ich die Clone Funktion nicht bei jeder Tierart implementieren muss?
    Ansätze hat es ja heute schon genug gegeben nur leider keine wirklich funktionierende Version.

    Mit bestem Dank THE_ONE



  • Joa ich hab da mal was probiert, eventuell ist es ja das was du brauchst.Hier mal meine Lösung.

    abstract class Device : ICloneable
        {
            public int OneProperty { get; set; }
            public int SecondProperty { get; set; }
            public Device()
            {
    
            }
    
            #region ICloneable Members
    
            public object Clone()
            {
                Type t = this.GetType();
                Device d = Activator.CreateInstance(t) as Device;
                d.OneProperty = this.OneProperty;
                d.SecondProperty = this.SecondProperty;
                return d;
            }
    
            #endregion
        }
         class Device2 : Device
         {
         }
         class Device3 : Device
         {
         }
    

    Verwendung:

    class Program
        {
            static void Main(string[] args)
            {
    
                Device dev = new Device2();
                dev.OneProperty = 100;
                dev.SecondProperty = 1000;
    
                Device dev3 = new Device3();
                dev3.OneProperty = 1;
                dev3.SecondProperty = 2;
    
                Device dev2 = dev3.Clone() as Device;
                Console.Read();
            }
    }
    

    Einfach mal nen Breakpoint bei dem Console.Read() setzen und reinschauen, dann sieht man das es wirklich vom Typ Device3 ist. Und dann kann man mal noch

    dev3
    

    durch

    dev
    

    ersetzen um den Effekt zu sehen.


Anmelden zum Antworten