none
Verschiedende Eigenschaften der selben Klasse RRS feed

  • Frage

  • Hallo,

    Ich bin noch ziehmlicher Anfänger und habe da ein Problem mit "Klassen"

    Zum Sachverhalt:

    Ich habe mir eine Klasse Namens "Fahrzeug" angelegt und dieser die Eigenschaften Name,Länge, Breite , Höhe , LeerGewicht und Zuladung angelegt.

    Nun habe ich ein Objekt der Klasse instanziert und dieser dann die Eigenschaften eines LKW's zu gewiesen und diese Fahrzeuge in einer Liste
    (Fahrzeugpark as new List(of Fahrzeug) gelegt.
    So habe ich mir dann ein ganzen Fuhrpark von Fahrzeugen zu gelegt.

    Nun zu meinem Problem.

    Sagen wir mal ich benötige zwei mal den selben Lkw für eine bestimmte Berechnung und diese dann in einer Zweite Liste packen dann würde ich das so machen (nur als Beispiel) :

    Dim Transportkolone as new List(of Fahrzeug)

    Transportkolone.add(Fuhrpark.Item(2))
    und das zweite (selbe Fahrzeug)
    Transportkolone.add(Fuhrpark.Item(2))

    nun habe ich aber das Problem wenn ich bei Fahrzeug 1 (Transportkolone.item(0).Beladung = 500) 500 Kg Gewicht "einlade dann macht er das Auch bei Fahrzeug 2

    Ich habe auch probiert :
    Dim i as new Fahrzeug ( Dacht mir einfach eine Neue Instanz von Fahrzeug schaffen)
    i = Fuhrpark.item(0)
    Transportkolone.add(i)

    geht aber auch nicht

    Immer das Gleiche: Ändere ich eine Eigenschaft
    dann ändern sich alle des selben Fahrzeugs

    Wie kann ich da Abhilfe schaffen?

    Vielen Dank für die Hilfe





    Mittwoch, 19. August 2009 10:16

Antworten

  • Hallo Daniel,

    ob LKW, Waggons oder Flugzeuge ist dabei vollkommen egal ;-)

    Zu ByRef und ByVal:
    Das hängt zwar teilweise zusammen ist aber nicht identisch.

    Das .NET Framework unterscheidet zum einen zwei grundlegende Typen,
    Referenz- bzw. Verweistypen (Class in Visual Basic) und Wertetypen (Structure).
    http://msdn.microsoft.com/de-de/library/t63sy5hs.aspx
    und in 99 Prozent der Fälle wirst man Class verwenden.

    Das die Schlüsselwörter ByVal bzw. ByRef bei Parametern wiederum
    geben an, wie der Wert übergeben wird:
    Übergeben von Argumenten als Wert und als Verweis
    und auch hier wird man in den meisten Fällen ByVal verwenden,
    um eine unbeabsichtige Veränderung zu verhinden. Und das wird
    von Visual Basic deswegen als Vorgabe eingesetzt.
    Und ByRef setzt man selten und kontolliert nur da, wenn es wirklich beabsichtigt ist.

    Zu 1.)
    Du mußt alle Werte übertragen, die das neue Objekt übernehmen soll.
    Nach Deinem Codeschnippsel sind das einige mehr, als in meinem kurz gehaltenen Beispiel.
    Und Du kannst den Code, den Du bereits hast in den Konstruktor übertragen.
    Und damit existiert der Code nur einmalig.

    Zu 2.)
    Die IClonable Schnittstelle wird an einigen Stellen im .NET Framework genutzt - Pflicht ist sie nicht.
    Da sie für die allgemeine Anwendung zu unbequem ist, denn man müsste schreiben
    DirectCast(i.Clone(), Fahrzeug)

    habe ich sie nur als explizite Schnittstelle definiert, die die typisierte (As Fahrzeug) aufruft.

    Zu ToString()
    Jede .NET Klasse erbt Object.ToString .
    Wobei die dortige Omplementation nur den Klassennamen ausgibt.
    Für eigene Klassen kann man sie nutzen, um die Inhalte (alle oder die wichtigsten) auszugeben.

    Das ist wie im Beispiel zum einen hilfreich, um sich die Inhalte im Programm ausgeben  zu lassen.
    Die integrierten Typen insbesondere die Standardtypen unterstützen noch mehr:
    Formatierung von Typen
    Was für Deine Waggons aber weniger in Frage kommt.

    Gruß Elmar

    • Als Antwort markiert B00NE Donnerstag, 20. August 2009 11:46
    Donnerstag, 20. August 2009 10:57

Alle Antworten

  • Hallo,

    wenn Du eine Instanz einer Klasse einer anderen Liste (oder jeder anderen Variable) zuweist,
    so wird nur die Referenz der Variable übertragen. Die Inhalte verändert sich nicht.

    Um eine Kopie einer Instanz zu erstellen, verwendet man idR. einen sog. Copy-Konstrutor,
    der eine neue Instanz erstellt und alle Eigenschaften der Klasse kopiert.
    .NET sieht dafür auch die IClonable Schnittstelle vor, die leider den Nachteil hat, nicht strengtypisiert zu sein.
    Damit es einfacher ist, bietet sich eine zusätzliche typisierte Variante an.

    Für eine reduzierte Variante Deiner Klasse könnte das dann wie folgt aussehen:

    Public Class Fahrzeug
        Implements ICloneable
    
    
        Public Sub New()
        End Sub
    
        Public Sub New(ByVal fahrzeug As Fahrzeug)
            Me._name = fahrzeug._name
            Me._zuladung = fahrzeug._zuladung
        End Sub
    
        Private _name As String
        Public Property Name() As String
            Get
                Return If(Me._name, "Ohne Namen")
            End Get
            Set(ByVal value As String)
                Me._name = value
            End Set
        End Property
    
        Private _zuladung As Double
        Public Property Zuladung() As Double
            Get
                Return Me._zuladung
            End Get
            Set(ByVal value As Double)
                Me._zuladung = value
            End Set
        End Property
    
        Public Function Clone() As Fahrzeug
            Return New Fahrzeug(Me)
        End Function
    
        Private Function ICloneableClone() As Object Implements System.ICloneable.Clone
            Return Me.Clone()
        End Function
    
        Public Overrides Function ToString() As String
            Return String.Format(Nothing, _
                "[Fahrzeug: Name: {0}, Zuladung: {1}", _
                Me.Name, Me.Zuladung)
        End Function
    End Class

    Und etwas Beispielcode wie man damit arbeitet:

        Public Shared Sub TestFahrzeug()
            Dim Fuhrpark As New List(Of Fahrzeug)
    
            Dim f As New Fahrzeug() With {.Name = "HH EK 247", .Zuladung = 300}
            Fuhrpark.Add(f)
            ' oder kürzer
            Fuhrpark.Add(New Fahrzeug() With {.Name = "HF XY 134", .Zuladung = 1300})
    
            For Each f In Fuhrpark
                Console.WriteLine("Fuhrpark: {0}", f)
            Next
    
            Dim kolonne As New List(Of Fahrzeug)
            ' Kopie des ersten Fahrzeugs anlegen
            kolonne.Add(Fuhrpark(0).Clone())
            kolonne(0).Zuladung = 100
    
            ' Suchen über eine Funktion
            f = Fuhrpark.Find(Function(suche) (suche.Name = "HF XY 134")).Clone()
            f.Name = "HF ZZ 4711"
            kolonne.Add(f)
            For Each f In kolonne
                Console.WriteLine("Kolonnenfahrzeug: {0}", f)
            Next
        End Sub
    	
    Gruß Elmar

    Mittwoch, 19. August 2009 16:59

  • Dank dir Elma !

    Das mit dem byRef/byVal habe ich mir schon fast gedacht aber konnte mit meinem beschränkten wissen nicht zu einer Lösung kommen.


    Ich hate mich Gestern Nachmittag auch nochmal ran gesetzt und folgende Lösung gefunden die aber wie ich zugebe bei weiten nicht so
    Professionell gelöst wurde wie deine. (...und wie ihr seht handelt es sich in meinen Program nicht um LKW's sondern Eisenbahnwagons :-) )


    Dim Der_Zug as new List (of Fahrzeug)
    Dim i As New Fahrzeug
    Dim ii As Fahrzeug = cboWagen.SelectedItem
    
                i.Achsen = ii.Achsen
                i.Art = ii.Art
                i.Bildpfad = ii.Bildpfad
                i.Bremsstellungleer = ii.Bremsstellungleer
                i.BrH = ii.BrH
                i.BrLeer = ii.BrLeer
                i.BrVoll = ii.BrVoll
                i.Kupplung = ii.Kupplung
                i.LadungsArt = ii.LadungsArt
                i.LüP = ii.LüP
                i.Masse = ii.Masse
                i.MaxMasse = ii.MaxMasse
                i.Name = ii.Name
                i.Ps = ii.Ps
                i.Streckenklasse = ii.Streckenklasse
                i.Vmax = ii.Vmax
    
                Der_Zug.Add(i)





    Ich hab einfach Zwei Instanzen erstellt und jeden Einzelnen Member dem anderen Zugewiesen.


    ich werde aber deine Variante verwenden ( da 1. Deine Variante weitaus professioneller gelöst wurden und 2. Ich es ja gleich richtig lernen will.)

    Also kann man Zusammenfassend sagen das ich in meiner Klasse nur:

    1. ein neuen Konstruktor einfügen muß  der ein neues Fahrzeug erstellt ( byValue)
    in denen dann alle Member der neuen Fahrzeugklasse übergeben werden.



    Public Sub New(ByVal fahrzeug As Fahrzeug)
            Me._name = fahrzeug._name
            Me._zuladung = fahrzeug._zuladung
        End Sub
    2. eine Methonde Names Clone erstellen erstellen die dieses Neu Fahrzeug zurück gibt.



     Public Function Clone() As Fahrzeug
            Return New Fahrzeug(Me)
        End Function
    

    So und nun wird es Interessant :

    Wie wird den die folgende Function aufgerufen ?


    Private Function ICloneableClone() As Object Implements System.ICloneable.Clone
            Return Me.Clone()
        End Function
    

    Und wo zu dient diese Function?




    Public Overrides Function ToString() As String
            Return String.Format(Nothing, _
                "[Fahrzeug: Name: {0}, Zuladung: {1}", _
                Me.Name, Me.Zuladung)
        End Function
    


    Vielen Dank nochmals für die Hilfe


    Daniel

    • Bearbeitet B00NE Donnerstag, 20. August 2009 10:18
    Donnerstag, 20. August 2009 10:07
  • Hallo Daniel,

    ob LKW, Waggons oder Flugzeuge ist dabei vollkommen egal ;-)

    Zu ByRef und ByVal:
    Das hängt zwar teilweise zusammen ist aber nicht identisch.

    Das .NET Framework unterscheidet zum einen zwei grundlegende Typen,
    Referenz- bzw. Verweistypen (Class in Visual Basic) und Wertetypen (Structure).
    http://msdn.microsoft.com/de-de/library/t63sy5hs.aspx
    und in 99 Prozent der Fälle wirst man Class verwenden.

    Das die Schlüsselwörter ByVal bzw. ByRef bei Parametern wiederum
    geben an, wie der Wert übergeben wird:
    Übergeben von Argumenten als Wert und als Verweis
    und auch hier wird man in den meisten Fällen ByVal verwenden,
    um eine unbeabsichtige Veränderung zu verhinden. Und das wird
    von Visual Basic deswegen als Vorgabe eingesetzt.
    Und ByRef setzt man selten und kontolliert nur da, wenn es wirklich beabsichtigt ist.

    Zu 1.)
    Du mußt alle Werte übertragen, die das neue Objekt übernehmen soll.
    Nach Deinem Codeschnippsel sind das einige mehr, als in meinem kurz gehaltenen Beispiel.
    Und Du kannst den Code, den Du bereits hast in den Konstruktor übertragen.
    Und damit existiert der Code nur einmalig.

    Zu 2.)
    Die IClonable Schnittstelle wird an einigen Stellen im .NET Framework genutzt - Pflicht ist sie nicht.
    Da sie für die allgemeine Anwendung zu unbequem ist, denn man müsste schreiben
    DirectCast(i.Clone(), Fahrzeug)

    habe ich sie nur als explizite Schnittstelle definiert, die die typisierte (As Fahrzeug) aufruft.

    Zu ToString()
    Jede .NET Klasse erbt Object.ToString .
    Wobei die dortige Omplementation nur den Klassennamen ausgibt.
    Für eigene Klassen kann man sie nutzen, um die Inhalte (alle oder die wichtigsten) auszugeben.

    Das ist wie im Beispiel zum einen hilfreich, um sich die Inhalte im Programm ausgeben  zu lassen.
    Die integrierten Typen insbesondere die Standardtypen unterstützen noch mehr:
    Formatierung von Typen
    Was für Deine Waggons aber weniger in Frage kommt.

    Gruß Elmar

    • Als Antwort markiert B00NE Donnerstag, 20. August 2009 11:46
    Donnerstag, 20. August 2009 10:57
  • Dank dir Elmar, du hast mir sehr geholfen


    Grüße aus dem Sonnigen Berlin



    Daniel


    Donnerstag, 20. August 2009 11:47