abstract + ICloneable Clone
-
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.
-
Erstmal danke für deine Hilfe, hatte schon voll deinen letzten Beitrag übersehen.
Sowas in der Art hatte ich auch schon, nur leider hat es bei mir nie funktioniert da ich den type nicht casten konnte.
Mir hatte leider das as gefehlt. Hatte es bis jetzt nicht gekannt.In C schreibt man einach (Tpye) vor ein Object und das wars, (z.b.: (int)1.11 macht aus dem Wert 1.11 einen Integer).
Habe die ganze Zeit folgendes versucht:Device d = (Device)Activator.CreateInstance(t);
Leider ohne Erfolg. Bei int, float,double und so funktioniert der normale cast aber noch.
Verwendet man den as Operator nur für Objekte die mit new erzeugt werden/wurden?
-
Der as-Opertaor macht nix anderes als einen Cast, aber ohne das eine Exception geworfen wird. Er gibt stattdessen null zurück.
Demnach funktioniertDevice d = (Device)Activator.CreateInstance(t);
sehr wohl, es sei denn du hast falsche Typinformationen übergeben.