| |
VB.NET - Ein- und UmsteigerRe: [OOP]: Zwei Objekt, aber ein Wert? | | | Autor: keco | Datum: 07.03.12 17:35 |
| Ja, natürlich ist sie im Framework vorhanden und den Entwicklern bekannt. Das macht eben die Dokumentation aus. Ich wollte auch nicht vehement gegen den Einsatz der Schnittstelle protestieren.
Eine Unterscheidung ob flach oder tief ist meiner Meinung nach schon relevant. Man kann nicht davon ausgehen, dass aus der Klasse selbst die Art der Kopie hervorgeht. Das von dir genannte Beispiel ist trivial und als flache Kopie nur logisch. Es gibt aber immer Entwickler und Anwender, die unterschiedliche Auffassungen/Meinungen haben (das merkst du sicherlich auch hier im Forum), weshalb die Art immer dokumentiert sein sollte. | |
[OOP]: Zwei Objekt, aber ein Wert? | | | Autor: Streamfighter | Datum: 03.03.12 23:51 |
| Hallo,
ich bin gerade auf folgendes Problem gestoßen:
Hier mal der Code vereinfacht:
Public Class Form1
Dim o1 As Klasse1 = New Klasse1(1)
Dim o2 As Klasse1 = New Klasse1(2)
Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) _
Handles Me.Load
o2 = o1
o1.Feld1 = 9
'o2.Feld1 =???????
End Sub
End Class
Class Klasse1
Public Feld1 As UShort
Sub New(ByVal f As UShort)
Feld1 = f
End Sub
End Class Wider allen meiner Erwartungen ist o2.Feld1 an der Stelle mit den Fragezeichen auch 9 wie o1.Feld1,
und nicht etwa 2.
Woran liegt das? Ich dachte eig die OOP soweit verstanden zu haben und jetzt das...
Und wie müsste ich vorgehen, dass sich o2.Feld1 wie eine gewöhnliche Variable verhält und Ihren Wert beibehält.
Danke für eure Hilfsbereitschaft
Beitrag wurde zuletzt am 03.03.12 um 23:51:14 editiert. | |
Re: [OOP]: Zwei Objekt, aber ein Wert? | | | Autor: Preisser | Datum: 04.03.12 00:02 |
| Hallo,
normale Objekte sind ja referenzbasiert, d.h. man speichert immer nur eine Referenz auf ein Objekt, das irgendwo im Heap liegt (eigentlich müsste das aber in jedem OOP-Tutorial ganz am Anfang behandelt werden). Mit
o2 = o1 wird ja die Referenz auf ein Objekt, die in o1 abgelegt ist, in o2 kopiert, also zeigen sowohl o1 als auch o2 auf das selbe Objekt. Wenn du mit o1.Feld1 = 9 die Variable in dem Objekt änderst, auf das o1 zeigt, ist es natürlich klar, dass auch o2.Feld1 = 9 ist, da o1 und o2 ja auf das selbe Objekt zeigen.
Streamfighter schrieb:
Zitat: | | Und wie müsste ich vorgehen, dass sich o2.Feld1 wie eine gewöhnliche Variable verhält und Ihren Wert beibehält. | |
Wie meinst du das? Also wenn du einen Werttyp statt eines Referenztyps verwenden willst, müsstest du eine Structure verwenden.
Structure Struct1
...
End Structure In dem Fall würde bei der Deklaration
Dim myVar As Struct1 keine Referenz abgelegt werden, sondern die Datenstruktur direkt.
Allerdings sollte man das nur verwenden, wenn es erforderlich ist (z.B. aus Effizienzgründen), da damit beispielsweise keine Vererbung möglich ist (da ja im Voraus bekannt sein muss, wieviel Bytes die Datenstruktur belegt, während eine Referenz immer die gleiche Anzahl Bytes (4 bzw. 8) belegt und man damit auf unterschiedlich "große" Objekte verweisen kann).
Wenn du nur eine Kopie eines Objekts erstellen willst, kannst du auch die protected MemberwiseClone-Methode des Objekts aufzurufen. Z.B. bei
Class Klasse1
Public Feld1 As UShort
Sub New(ByVal f As UShort)
Me.Feld1 = f
End Sub
Public Function Clone() As Klasse1
Return DirectCast(Me.MemberwiseClone(), Klasse1)
End Function
End Class und dem Code
Private o1 As Klasse1 = New Klasse1(1)
Private o2 As Klasse1 = Nothing
Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) _
Handles Me.Load
o2 = o1.Clone()
o1.Feld1 = 9
MessageBox.Show("" & o2.Feld1)
End Sub würde o2.Feld1 weiterhin 1 sein, da dann eine flache Kopie des Objekts erstellt und die Referenz darauf in o2 abgelegt werden würde.
(Man sollte auch am besten auf Objektattribute immer per Properties zugreifen.)
Beitrag wurde zuletzt am 04.03.12 um 00:24:02 editiert. | |
Re: [OOP]: Zwei Objekt, aber ein Wert? | | | Autor: Manfred X | Datum: 04.03.12 05:14 |
| Hallo!
Du hast selbst bereits festgestellt, dass Du die (elementaren) Grundlagen
des OOP noch nicht verstanden hast.
Preisser hat in seiner Antwort weitere Themenbereiche eingeführt
(Unterscheidung Value- und Referencetype, Clone-Methode), die ebenfalls nicht
so ganz einfach zu durchschauen sind.
Am besten wäre es wohl, Du arbeitest ein Lehrbuch zu den Grundlagen
des OOP durch und liest parallel dazu die entsprechenden Übersichtsartikel
in der MSDN.
Überblick über OOP im Net-Framework:
http://msdn.microsoft.com/en-us/library/dd460654.aspx
Überblick über das Typ-System im gemeinsamen Laufzeitsystem (CLR):
http://msdn.microsoft.com/en-us/library/zcx1eb1e.aspx
Übersicht über Werttypen und Referenztypen:
http://msdn.microsoft.com/en-us/library/t63sy5hs.aspx
Gegenüberstellung von Structure und Class:
http://msdn.microsoft.com/en-us/library/2hkbth2a.aspx
Erstellen von Klassen:
http://msdn.microsoft.com/en-us/library/xtka85tz.aspx
Thema: "Lebensdauer" von Instanzen einer Klasse:
http://msdn.microsoft.com/en-us/library/hks5e2k6.aspx
Thema: Klonen
http://www.codeproject.com/Articles/4666/An-insight-into-cloning-objects-in-NET
http://msdn.microsoft.com/en-us/library/system.icloneable.aspx
http://msdn.microsoft.com/en-us/library/system.icloneable.clone.aspx
Thema: Vererbung
http://msdn.microsoft.com/en-us/library/5x4yd9d5%28v=VS.90%29.aspx
Viel Spass!
==========================================================================
In deinem Code führt die Zuweisung o2 = o1 dazu, dass
o2 eine Referenz auf die Instanz erhält, auf die auch o1 zeigt.
Sollte auf es auf die Instanz von Klasse1, auf die o2 zuvor "referenziert" war,
keine weitere Referenz geben, wird diese Instanz zur "Beseitigung" durch den
"Garbage Collector" freigegeben, d.h. sie ist (mit allen darin enthaltenen Daten) futsch.
==========================================================================
In VB.Net gibt es übrigens keine "gewöhnlichen Variablen".
Selbst ein "Primitive" (= Framework-Bezeichnung für elementare Datentypen)
wie System.UInt16 (in VB auch gelegentlich als "UShort" bezeichnet), ist eine Structure,
die z.B. diverse Methoden zur Verfügung stellt:
http://msdn.microsoft.com/de-de/library/system.uint16.aspx
Primitives:
http://msdn.microsoft.com/de-de/library/system.type.isprimitive%28v=vs.90%29.aspx
Zeichenfolgen-Variablen (Datentyp: System.String; Klasse) sind in Net Referenztypen, mit einem
speziellen Verhalten: Sie sind unveränderlich. Bei jeder Änderung der enthaltenen Zeichenfolge wird
deshalb automatisch die Zeichenfolge neu erstellt.
[I]Methoden, die ein String-Objekt scheinbar ändern, geben in Wirklichkeit ein neues String-Objekt zurück.[/I]
http://msdn.microsoft.com/de-de/library/system.string%28v=VS.80%29.aspx | |
Re: [OOP]: Zwei Objekt, aber ein Wert? | | | Autor: Streamfighter | Datum: 04.03.12 12:21 |
| Vielen Dank an euch drei. Ich werde mich mal weiterhin mit dem Thema befassen. Ich hab ja jetzt genügend Infomaterial.
Wenn ich dann noch Fragen habe werde ich sie hier posten. | |
Re: [OOP]: Zwei Objekt, aber ein Wert? | | | Autor: Streamfighter | Datum: 07.03.12 09:27 |
| OK. Ich hab mir die Links durchgelesen und mir wurde dabei einiges klarer. Jedoch musste ich auch feststellen, dass ich mir alles nochmal anschauen sollte.
Bei meinem aktuellen Projekt, einer 2D Version des Dreikörperproblems
hab ich allerdings ein Problem das ich noch nicht lösen konnte:
Ich habe ein Klasse Körper geschrieben, die alle Eigenschaften des Körpers enthält, also Geschwindigkeit, Ort, Masse...Im Sub Position werden dann für jedes Frame die neuen Orte der Körper berechnet. Da ich dabei immer nur jeden Körper nacheinander berechnen kann, erstellte ich zwei Liste mit allen drei Körpern.
neu as new List(Of Körper)
alt as new List(Of Körper)
Sub Position 'Hier werden die neuen Orte für alle Körper aus Liste alt
' berechnet und in Liste neu gespeichert
alt = neu Die letzten zwei Zeilen werden dann wiederholt aufgerufen. Hier gibt es dann folgendes Problem:
da ich alt=neu geschrieben habe sind beide Listen immer identisch, d.h. Liste alt ändert sich während Sub Position, obwohl ich nur Liste neu verändere. Das muss natürlich vermieden werden.
Ihr habt mir empfohlen .clone zu verwenden. Leider habe ich noch nicht herausgefunden, wie man ganze Listen klont. Das einzige was mir einfallen würde, wäre eine For Each Schleife mit de ich jedes einzelne Member der Liste klone, was mir aber ungeeignet scheint.
Könnte mir bitte nochmal jemand sagen wie ich dabei am besten vorgehe. Oder mir einen anderen Ansatz vorschlagen? | |
Re: [OOP]: Zwei Objekt, aber ein Wert? | | | Autor: Manfred X | Datum: 07.03.12 10:29 |
| Hallo!
Du mußt wohl oder übel die Einträge in der Liste klonen -
und eventuell mußt Du sogar zusätzlich in der Klasse "Körper"
die "ICloneable"-Schnittstelle implementieren.
MfG
Manfred | |
Re: [OOP]: Zwei Objekt, aber ein Wert? | | | Autor: Streamfighter | Datum: 07.03.12 15:21 |
| @Micke: Tut mir leid, falls ich mich unverständlich ausgedrückt habe. Zur Erläuterung:
•Position und Ort sind in diesem Zusammenhang für mich dasselbe
•Ja, es werden die Orte berechnet. Ich schrieb "Körper berechnet",weil die Orte ja sozusagen Teil der Körper sind. Außerdem werden ja nicht nur Orte berechnet, sondern auch Geschwindigkeit und so weiter,deshalb erschien es mir richtiger Körper zu schrieben.
•Zu den Listen: Du kannst sie auch gerne umbenennen. Liste_alt soll die Körper in dem Stand vor der Änderung ihrer Eigenschaften durch Sub Position enthalten. Liste_neu enthält die Körper, deren Eigenschaften in Sub Position verändert wurden.
So ich hab jetzt jeden Eintrag der Liste einzeln geklont mithilfe des ersten Codes von DaveS.
Ich hab mal versucht alles wegzulassen was möglich war. Ohne das <Serializable()> und die Implementierungen geht er genauso. Ist das das was du in deinem zweiten Post gemeint hast? Oder sollte ich mir ein eigenes CloneCopy()-Interface (heißt das so?) schreiben? Mit dem <Serializable()> konnte ich leider fast nichts anfangen. Ist das ein Attribut? Ändert das iwas am Programmablauf, oder ist das nur für die IDE?
Also soweit funktioniert jetzt alles. Vielen Dank | |
Re: [OOP]: Zwei Objekt, aber ein Wert? | | | Autor: Manfred X | Datum: 07.03.12 15:36 |
| Hallo!
Die Instanz einer als "serialisierbar" gekennzeichneten Klasse kann z.B. in
eine Folge von Bytes gewandelt (BinaryFormatter) und so gespeichert werden
(siehe Code von DaveS).
Auf diese Weise lassen sich Kopien erstellen.
Wenn Du keine Klassen als Member hast, reicht einfaches "MemberwiseClone"
aus. Mach Dir den Unterschied zwischen "tiefer" und "flacher" Kopie
einer Instanz klar.
MfG
Manfred | |
Re: [OOP]: Zwei Objekt, aber ein Wert? | | | Autor: DaveS (Moderator) | Datum: 07.03.12 15:42 |
| < Serializable()> braucht man nur für das zweite Beispiel, das DeepClone() aufruft. Die .Clone() Methode dagegen braucht man nur für das erste Beispiel.
Ich weiß aber nicht was am zweiten weniger verständlich ist, die Zeile
Dim myobjects2 As List(Of MyObject) = DeepClone(Of List(Of MyObject))( _
myObjects) klont die ganze Liste, genauso wie die Zuweisung und Schleife
Dim myObjects1 As New List(Of MyObject)
For Each mo As MyObject In myObjects
myObjects1.Add(mo.Clone())
Next im ersten Beispiel. (Eigentlich nicht genau so, weil alles geklont wird, nicht nur Objekte, die "ICloneable" sind. Allerdings, obwohl anscheinend kürzer ist der Code wesentlich langsamer).
________
Alle Angaben ohne Gewähr. Keine Haftung für Vorschläge, Tipps oder sonstige Hilfe, falls es schiefgeht, nur Zeit verschwendet oder man sonst nicht zufrieden ist | |
Re: [OOP]: Zwei Objekt, aber ein Wert? | | | Autor: keco | Datum: 07.03.12 16:14 |
| Es besteht keine Notwendigkeit diese Schnittstelle zu implementieren. Daher, dass nur eine einzige Methode bereitgestellt wird, bei der nicht sichergestellt ist, ob eine flache oder tiefe Kopie des Objektes erstellt wird, würde dies nur zu Unsicherheit führen. Microsoft selbst rät dazu eine eigene Clone-Methode mit typisiertem Rückgabewert zu erstellen und in der Dokumentation zu vermerken, ob es sich um flache oder tiefe Kopien handelt.
Informationen dazu sind im Blog von Brad Abrams zu finden. | |
Re: [OOP]: Zwei Objekt, aber ein Wert? | | | Autor: DaveS (Moderator) | Datum: 07.03.12 16:22 |
| Ja, aber ich finde dieser ziemlich alte Beitrag ist etwas übertrieben, weil man ohnehin dokumentieren kann was .Clone() macht bei einer eigenen Klasse (und die Doku sollte man auch lesen ) Außerdem was sinnvoll/notwendig ist beim Klonen hängt von mehreren Faktoren ab. Ein DeepClone ist nicht unbedingt notwendig, auch wenn Unterobjekte vorhanden sind. Allerdings als Regel kann man sagen, dass wenn ein Unterobjekt ICloneable (oder was immer) implementiert, soll die .Clone() der Container-Klasse .Clone() der Unterklasse aufrufen. Das wäre irgendwie logisch, meine ich.
________
Alle Angaben ohne Gewähr. Keine Haftung für Vorschläge, Tipps oder sonstige Hilfe, falls es schiefgeht, nur Zeit verschwendet oder man sonst nicht zufrieden ist | |
Re: [OOP]: Zwei Objekt, aber ein Wert? | | | Autor: keco | Datum: 07.03.12 16:34 |
| Da stimme ich zwar zu, mir gefällt aber nicht, dass die Clone-Methode keinen typisierten Rückgabewert liefert. Ich persönlich würde selber Methoden erstellen, die eine flache und tiefe Kopie ermöglichen. Ansonsten könnte man zusätzlich (um mit dem Framework konform zu bleiben) das Interface implementieren und je nach Art die eigene Methode aufrufen.
Wie ich aber gerade in den unteren Beiträge gesehen habe wurde von dir auch eine generische DeepClone-Methode erstellt, die mir sehr gut gefällt. Da stellt sich mir gerade aber die Frage, wieso es keine (generische) ICloneable mit 2 Methoden (ShallowClone und DeepClone) gibt. Das würde ich persönlich für sinnvoller erachten. Immerhin wäre die Art der Kopie von vorneherein klar. | |
Re: [OOP]: Zwei Objekt, aber ein Wert? | | | Autor: Manfred X | Datum: 07.03.12 17:16 |
| Hallo!
Die ICloneable-Schnittstelle ist in Klassen des Net-Framework implementiert -
(z.B. Datatable, Image, String) insofern ist sie (incl. der Eigenart)
den Entwicklern vertraut.
Beim Clonen sollte man auch nicht einfach zwischen "flach" und "tief" unterscheiden,
sondern es muß stets klar sein, welcher Zweck im Einzelnen mit der
Implementierung verfolgt wird. (Die Clone-Impl. der Datatable kopiert das
Tabellen-Schema, nicht die Daten.)
MfG
Manfred | |
| Sie sind nicht angemeldet! Um auf diesen Beitrag zu antworten oder neue Beiträge schreiben zu können, müssen Sie sich zunächst anmelden.
Einloggen | Neu registrieren |
|
|
sevISDN 1.0
Überwachung aller eingehender Anrufe!
Die DLL erkennt alle über die CAPI-Schnittstelle eingehenden Anrufe und teilt Ihnen sogar mit, aus welchem Ortsbereich der Anruf stammt. Weitere Highlights: Online-Rufident, Erkennung der Anrufbehandlung u.v.m. Weitere InfosTipp des Monats TOP! Unser Nr. 1
Neu! sevDataGrid 3.0
Mehrspaltige Listen, mit oder ohne DB-Anbindung. Autom. Sortierung, Editieren von Spalteninhalten oder das interaktive Hinzufügen von Datenzeilen sind ebenso möglich wie das Erstellen eines Web-Reports. Weitere Infos
|