Laden...

Basic: Object an Object übergeben

Erstellt von Mighty Panther vor 15 Jahren Letzter Beitrag vor 15 Jahren 1.288 Views
Mighty Panther Themenstarter:in
22 Beiträge seit 2008
vor 15 Jahren
Basic: Object an Object übergeben

Hi!

Ich wusste nicht wie ich die Suchanfrage diesbezüglich stellen sollte, daher poste ich ein Thema, was vielleicht schon existiert. Dafür entschuldige ich mich vorab.

Wahrscheinlich ist mein Problem für die meisten ganz Easy, aber ich stehe irgendwie auf dem Schlauch.

Zur Vereinfachung, da meine eigene Klasse etwas komplexer ist, nehme ich mal eine Klasse Person (Name, Vorname, Adresse etc.) an.

Jede neue Person initialisiere ich mit…

Person person = new Person();
person.name = "name";
//etc.
//und trage diese dann in eine liste
liste.add(person);

Soweit stellt das jetzt auch kein Problem dar.
Nun dachte ich mir, wenn eine neue Person, zu einer Familie gehört, dann brauch ich doch nur den Vornamen zu ändern und der rest bleibt gleich.


Person person2 = new Person();
person2 = person;
person2.vorname = "detlef";
liste.add(person2);

Tja! Nun habe ich aber ungewollt in meiner Liste, zwei Personen mit dem selben Vornamen (Detlef), da auch der vorherige geändert wird?! Ist sicherlich irgendwo richtig Vererbung oder so, aber wie muss/kann ich das machen, denn das war ja nicht mein Ziel?

Nun könnte man sagen, lass das mit dem ersetzen weg und erzeuge einfach eine neue Person und trag halt alle Daten erneut ein, aber wie gesagt, ist meine Klasse etwas komplexer und dieser "bloss den geänderten Teil" zu ersetzen Weg, wäre für mich westenlich eleganter und schneller.

THX & LG
Mighty

49.485 Beiträge seit 2005
vor 15 Jahren

Hallo Mighty Panther,

bei person2 = person; wird die in der Referenzvariable person enthalte Referenz an die Referenzvarianle person2 zugewiesen. Beide Variablen zeigen anschließend auf dasselbe Objekt. Die Referenz auf das vorher von person2 referenzierte Objekt geht verloren.

Das ist in der Tat eine der wesentlichen Grundlagen von C#-

Verabschiede dich von deiner Idee mit dem Kopieren und initialisiere das neue Objekt neu.

herbivore

S
57 Beiträge seit 2006
vor 15 Jahren

Hi,

mit DeepCopy könnte es gehen aber weiß nicht wie "elegant bzw. sauber" das ist.

und hier noch eine Info: Kopie ohne ICloneable

serg

946 Beiträge seit 2008
vor 15 Jahren

Wenn du das häufig verwenden willst, dann verwende doch am einfachsten die Schnittstelle ICloneable .

49.485 Beiträge seit 2005
vor 15 Jahren

Hallo See Sharp,

aus den in Basistechnologien und allgemeine .NET-Klassen genannten Gründen sollte man das nicht einfach so tun.

herbivore

946 Beiträge seit 2008
vor 15 Jahren

Hallo herbivore

Ich habe mir Kopie ohne ICloneable angeschaut. Dabei ging es zuerst darum, die Gründe gegen ICloneable, dann darum eine Alternative vorzustellen.

Mich hat aber der Anfang nicht überzeugt. In folgender Liste sine ein paar Gründe dagegen von Ihnen aufgelistet:*Was es in der Realität nur einmal gibt, sollte es im Programm ebenfalls nur einmal geben.
-> Es geht in diesem Beispiel, wie auch sonst öffters nur darum, einen neuen Typ zu initialisieren, der eine andere Eigenschaft hat. Dadurch finde ich das Klonen durchaus angebracht

*Sprich der normale Referenzsematik-Vergleichoperator '==' liefert für das Objekt und seinen Klon nicht mehr true.
-> Falls das wichtig ist, kann man den ja überschreiben. Die Alternativen sind dabei noch aufwändiger

*ICloneable ist besser als die Objekte "von Hand" zu kopieren. Aber bei ICloneable wird immer noch das Objekt kopiert, was schlecht ist, wenn es sich um Objekte mit Identität handelt.
-> Das war ja der Ansatz am Anfang des Threads

Meine Kommentare sind darunter (Sie habe übrigens überall IClonable statt IClon++e++able geschrieben).

Meine jetztige Meinung (ich will mich noch überzeigen lassen) ist, dass man bei grösseren Anwendungen schon eine Alternative erwägen sollte, aber sonst (meistens) auf ICloneable zuwückgreifen sollte, weil das sowohl einfacher und schneller zu implementieren ist, als auch mehr Unterstützung der .NET-Klassen verfügt.
See Sharp

49.485 Beiträge seit 2005
vor 15 Jahren

Hallo See Sharp,

Dadurch finde ich das Klonen durchaus angebracht

tja, Ansichtssache. Ich nicht, und meine Gründe sind bekannt.

Falls das wichtig ist, kann man den ja überschreiben.

Es ging nicht darum, ob man den operator== überschreibt oder nicht, sondern um dem Satz davor:

Beim Klonen wird ja nicht nur der Zustand, sondern auch die Identität gedoppelt (oder härter: zerstört).

Das mit dem Gleichheitsoperator war nur eine Erläuterung für die Zerstörte Identität. Ich hätte auch Object.ReferenceEquals schreiben können, wenn es das damals schon gegeben hätte. 🙂

ICloneable ist besser als die Objekte "von Hand" zu kopieren. Aber bei ICloneable wird immer noch das Objekt kopiert, was schlecht ist, wenn es sich um Objekte mit Identität handelt.

Damit ist gemeint, wenn man sich entgegen des Rats für das Kopieren von Objekten entscheidet, ist es besser, das über ICloneable zu tun, als "von Hand". Aber am besten ist es, sich an den Rat zu halten. Und das ist auch meine Empfehlung hier. Nicht kopieren und deshalb auch nicht ICloneable zu implementieren.

Mein Rat oben war ja gerade, dass Objekt nicht zu kopieren, sondern das zweite Objekte neu zu initialisieren. Das sind für mich zwei verschiedene Paar Schuh.

Sie habe übrigens überall IClonable statt ICloneable geschrieben

Danke für den Hinweis. Der OP hatte IClonable geschrieben und ich hatte es falsch übernommen. Ist jetzt in meinen Beiträgen korrigiert. Den ebenfalls falschen Titel des OP hatte ich schon vor längerer Zeit mal korrigiert.

Meine jetztige Meinung (ich will mich noch überzeigen lassen)

Für mich ist ICloneable weniger eine technische/praktische Frage, sondern eine konzeptionelle. Und das Konzept sagt, dass wenn Objekte (in der Realität) eine Identität haben, dann sollte die Klasse kein ICloneable implementieren. Die Klasse sollte das nur tun, wenn die Objekte (in der Realität) eine Wertsemantik haben.

herbivore

946 Beiträge seit 2008
vor 15 Jahren

Hallo herbivore

Ich war die Letzten 2 Tage abwesend, wodurch ich erst jetzt Antworten kann:

Es ging nicht darum, ob man den operator== überschreibt oder nicht, sondern um dem Satz davor:

Beim Klonen wird ja nicht nur der Zustand, sondern auch die Identität gedoppelt (oder härter: zerstört).
Das mit dem Gleichheitsoperator war nur eine Erläuterung für die Zerstörte Identität. Ich hätte auch Object.ReferenceEquals schreiben können, wenn es das damals schon gegeben hätte. 😃

Wenn man den operator== überschreibt, sollte man auch den operator!= und Object.ReferenceEquals überschreiben. Dadurch existiert eine "zerstörte" Indentität positivistisch (gibt es dieses Wort auch in der Informatik?) gesehen nicht mehr. In Wahrheit aber schon. Mittlerweile ist mir klar geworden, dass Klonen nicht nur eine praktische, sondern eine weitaus tiefere Bedeutung hat. Ich habe sehr lange gebraucht, um das zu verstehen, aber dein Schluss brachte es auf den Punkt (siehe weiter unten).
Es besteht beim Programmieren ein ähnliches Problem, wie in der Biologie bein "echten" Klonen.


Auch die Klon-Technik in der Biologie ist nicht dazu fähig, eindeutige Kopien des Originals zu produzieren. Weder Körpermerkmale wie Grösse und Fellfarbe, noch das Verhalten können nicht verdoppelt werden, da nicht nur die Gene, sondern auch nicht deren Aktivitätsmuster ein Lebeweswen ausmachen.
Dies ist eigentlich trivial, da eineiige Zwillinge nicht zwingend identisch sein müssen.

- - Aus [URL]Katzenjammer bei den Tier-Klonern (Basler Zeitung)[/URL] - - - - - - - - - - - - - - - - -
Aber wie kommts, dass Klone anders aussehen und sich auch so verhalten? Schuld sind
Umwelteinflüsse, die auf die Gene einwirken und sie aktivieren. Man vermutet zum Beispiel,
dass die verbesserte Ernährung der Menschen im 19. Jahrhunderts dazu führte, dass ein
Wachstums-Gen aktiviert wurde. Diese Gen-Veränderung soll bis heute vererbt werden:
Seither nehmen die Körpermasse der Europäer von Generation zu Generation
durchschnittlich um wenige Millimeter pro Jahr zu.

Jetzt greife ich wieder deinen Schluss auf, der mich sozusagen auf die richtige Spur brachte:

Für mich ist ICloneable weniger eine technische/praktische Frage, sondern eine konzeptionelle. Und das Konzept sagt, dass wenn Objekte (in der Realität) eine Identität haben, dann sollte die Klasse kein ICloneable implementieren. Die Klasse sollte das nur tun, wenn die Objekte (in der Realität) eine Wertsemantik haben.

Das Konzept habe ich ja teilweise schon angesprochen. Doch ich finde die Einschrenkung, eine Klasse ohne Wertsemantik könne sehr wohl ICloneable implementieren, kritisch wäre das nur, wenn die Klasse in der Realität nicht nur wertbezogen sind, zu ungenau. Das Beispiel am Anfang war eine Person. Diese hat zwar physikalisch (wie alles andere) nur eine Wertsemantik, in der Ethik allerdings nicht. Auch spielt eine Rolle was genau gemeint ist; die Person oder der Name.
Ich würde mir einmal erlauben, folgende, genauere Einschrenkung zu definieren: Klassen, die keine weiteren Klassen besitzen, sondern nur Strukturen, können ICloneable implementieren.

Aber nicht nur das Konzept spielt eine Rolle, die eigentlich sogar nebensächlich ist, sondern im Vordergrund steht eher eine praktische Sichtweise.

  • Das Konzept sagt meiner Meinung nach, dass ein Klon vollkommen unnötig ist. Falls er nicht verändert wird, macht es gar keinen Sinn und falls doch, ist eine Klonung unnötig. In diesem Sinn würde ich sogar noch eine Hand-Definition vorziehen.
  • Aus der praktischen Sichtweise sieht das ganz anders aus: Ein Klon ist nur eine Vorstufe zu einer eventuellen entgültigen Definition, die einfach zu realisieren und anzuwenden ist.

Das ganze läuft also auf eine Glaubensfrage heraus, ob Praktisch oder Konteptionell.

See Sharp

49.485 Beiträge seit 2005
vor 15 Jahren

Hallo See Sharp,

Wenn man den operator== überschreibt, sollte man auch den operator!= und Object.ReferenceEquals überschreiben.

auch wenn es mir um den operator== eigentlich gar nicht ging: Die Schlussfolgerung, dass man dann auch operator!= überschrieben sollte, ist richtig. Object.ReferenceEquals ist jedoch einen statische Methode und kann nicht überschrieben werden. Die Forderung wäre aber auch dann nicht sinnvoll, wenn es möglich wäre, denn Object.ReferenceEquals ist ja gerade ein Vergleich, der unabhängig von der Definition von Gleicheit in einer bestimmten Klasse ist.

Das Beispiel am Anfang war eine Person. Diese hat zwar physikalisch (wie alles andere) nur eine Wertsemantik

Nein, eine Person hat gerade eine Identität, die vom Zustand (=Wert) unabhängig ist. Eine Person hat daher gerade keine reine Wertsemantik. Ich bleibe immer dieselbe Person, ob ich nun etwas mehr oder etwas weniger wiege, ob meine Haare kurz oder lang sind, ob ich meinen Namen ändere oder ob ich mich sonst irgendwie verändere. Der Zustand kann sich also ändern, ohne dass sich die Identität ändert.

Ein Integer hat dagegen eine reine Wertsemantik. Wenn sich der Wert von fünf in sechs ändert, ist das eine anderer Wert. Andersherum ist jede Fünf gleich gut, es gibt also keine Fünf mit einer bestimmten Identität, die man von einer anderen Fünf unterscheiden könnte.

Ich würde mir einmal erlauben, folgende, genauere Einschrenkung zu definieren: Klassen, die keine weiteren Klassen besitzen, sondern nur Strukturen, können ICloneable implementieren.

Nein, ob es eine flache oder tiefe Objektstuktur gibt oder nicht, ist in meinen Augen kein passendes Unterscheidungsmerkmal dafür, ob ICloneable ok ist oder nicht. Die Unterscheidung ist schon, ob die Objekte eine Identität oder eine reine Wertsemantik haben.

herbivore

0
767 Beiträge seit 2005
vor 15 Jahren

Was wahrscheinlich gemeint war ist, dass wenn man == überschreibt, man auch != überschreiben sollte, sowie, wenn man .Equals überschreibt, man auch .GetHashCode überschreiben sollte.

Wenn Objekte aber "reine Wertsemantik" haben, sollte man sie ohnehin als struct definieren, wodurch sich die ganze Clone Problematik in Wohlgefallen auflöst. Falls sie recht groß sind (viele Daten halten), kann Struct allerdings etwas inperformant werden. In dem Fall bietet sich immer noch die Möglichkeit, sie immutable zu implementieren.

Structs sollten meiner Meinung ausserdem keine Referenztypen beinhalten die nicht ebenfalls Immutable sind (ist zwar erlaubt, kann aber verwirrend sein, da dort dann ja wieder nur die Referenzen kopiert werden).

Falls man wirklich eine Clone() braucht, sollte man sich überlegen, ICloneable explizit zu implementieren und bei der implizit implementieren Clone() den tatsächlichen Typ statt object zu verwenden, um unnötige casts zu vermeiden.

Abgesehen davon hängt es sehr oft nicht von der Klasse sondern von der Situation ab, ob man eine flache, tiefe oder auch gemischte Kopie braucht. ICloneable kann in dann nicht die Lösung sein, weil es die Situation nicht kennt und nicht weiss wie es kopieren soll.

loop:
btst #6,$bfe001
bne.s loop
rts