none
Probleme bei Eingenschaftzugriff in vererbten Klassen RRS feed

  • Frage

  • Hallo,

    ich habe eine Basisklasse, die in weitere Klassen vererbt wird. Die Basisklasse besitzt eine Eigenschaft "Parent" als Objekt, das in den anderen Klassen durch die exakte Klassenzuordnung überschrieben wird. Nach dem Überschreiben wird Parent nicht mehr in der Basisklasse erkannt. Wenn ich die Zeile     "Public Shadows Parent As clsKlasse2" ausblende funktioniert alles. Wieso ist in der Basisklasse die Parent-Eigenschaft nicht mehr vorhanden? Die Namensabfage in der clsKlasse1 funktioniert.

    Public Class Form1
        Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
            Dim obj1 = New clsKlasse1 : Dim obj2 = New clsKlasse2
            obj1.Parent = obj2
            obj1.ZeigeName()
        End Sub
    End Class
    
    Public Class clsBasis
        Public Name As String = "" : Public Parent As Object = Nothing
        Public Sub ZeigeName()
            If TypeOf Me Is clsKlasse1 Then MsgBox("Me Is clsKlasse1")
            MsgBox(Me.Parent.name)
        End Sub
    End Class
    
    Public Class clsKlasse1 : Inherits clsBasis
        Public Sub New()
            Me.Name = "clsKlasse1"
        End Sub
        Public Shadows Parent As clsKlasse2
    End Class
    
    Public Class clsKlasse2 : Inherits clsBasis
        Public Sub New()
            Me.Name = "clsKlasse2"
        End Sub
    End Class


    Peter

    Sonntag, 1. Juli 2012 17:58

Antworten

  • Falls der Shadows benötigt wird so ginge das in etwa so:


    Public Class clsKlasse1
      Inherits clsBasis

      Private mobjParent As clsKlasse2

      Public Shadows Property Parent As clsKlasse2
        Get
          Return mobjParent
        End Get

        Set(ByVal pValue As clsKlasse2)
          mobjParent = pValue
          MyBase.Parent = mobjParent
        End Set
      End Property

      Public Sub New()
        Me.Name = "clsKlasse1"
      End Sub
    End Class

    Sonntag, 1. Juli 2012 21:00

Alle Antworten

  • Hi Peter,

    ohne mich jetzt im Detail damit auseinander gesetzt zu haben.

    Ich denke:

    Public Shadows Parent As clsKlasse2

    sollte

    Public Shadow Parent as Objekt

    heißen.

    MFG

    Björn

    Sonntag, 1. Juli 2012 18:44
  • Hallo Peter,

    wegen des Shadows ist die Parent Variable in der Basisinstanz Nothing.

    Der Shadows versteckt das Parent Property von clsBasis für die Objekte von clsKlasse1. Der Button1_Click setzt nur die Parentvariable von objKlasse1 und die Parentvariable von clsBasis bleibt auf Nothing.

    Daher erzeugt ZeigeName eine Ausnahme.

    Brauchst du denn den Public Shadows Parent As clsKlasse2
    in clsKlasse1 wirklich? (Dann als Property definieren welches im Property Set MyBase.Parent setzt.)

    Du könntest Parent in clsBasis als clsBasis definieren.

    Würde auch in den Projekteigenschaften Option Strict on stets empfehlen. Dies hilft Fehler zu vermeiden.


    Public Class Form1
      Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Dim obj1 = New clsKlasse1
        Dim obj2 = New clsKlasse2

        obj1.Parent = obj2
        obj1.ZeigeName()
      End Sub
    End Class

    Public Class clsBasis
      Public Name As String = ""
      Public Parent As clsBasis = Nothing

      Public Sub ZeigeName()
        If TypeOf Me Is clsKlasse1 Then MsgBox("Me Is clsKlasse1")
        MsgBox(Me.Parent.Name)
      End Sub
    End Class


    Public Class clsKlasse1
      Inherits clsBasis

      Public Sub New()
        Me.Name = "clsKlasse1"
      End Sub
    End Class


    Public Class clsKlasse2
      Inherits clsBasis

      Public Sub New()
        Me.Name = "clsKlasse2"
      End Sub
    End Class







    • Bearbeitet Markus222 Montag, 2. Juli 2012 08:03
    Sonntag, 1. Juli 2012 20:19
  • Falls der Shadows benötigt wird so ginge das in etwa so:


    Public Class clsKlasse1
      Inherits clsBasis

      Private mobjParent As clsKlasse2

      Public Shadows Property Parent As clsKlasse2
        Get
          Return mobjParent
        End Get

        Set(ByVal pValue As clsKlasse2)
          mobjParent = pValue
          MyBase.Parent = mobjParent
        End Set
      End Property

      Public Sub New()
        Me.Name = "clsKlasse1"
      End Sub
    End Class

    Sonntag, 1. Juli 2012 21:00
  • Hier noch mit Compile Options Option Strict On. Ohne Shadows.


    Public Class Form1
      Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Dim obj1 = New clsKlasse1
        Dim obj2 = New clsKlasse2

        obj1.Parent = obj2
        obj1.ZeigeName()
      End Sub
    End Class


    Public Class clsBasis
      Public Name As String = ""
      Public Parent_Basis As clsBasis = Nothing

      Public Sub ZeigeName()
        If TypeOf Me Is clsKlasse1 Then MsgBox("Me Is clsKlasse1")
        MsgBox(Me.Parent_Basis.Name)
      End Sub
    End Class


    Public Class clsKlasse1
      Inherits clsBasis

      Private mobjParent As clsKlasse2

      Public Property Parent As clsKlasse2
        Get
          Return mobjParent
        End Get

        Set(ByVal pValue As clsKlasse2)
          mobjParent = pValue
          MyBase.Parent_Basis = mobjParent
        End Set
      End Property

      Public Sub New()
        Me.Name = "clsKlasse1"
      End Sub
    End Class


    Public Class clsKlasse2
      Inherits clsBasis

      Public Sub New()
        Me.Name = "clsKlasse2"
      End Sub
    End Class


    • Bearbeitet Markus222 Sonntag, 1. Juli 2012 21:54
    Sonntag, 1. Juli 2012 21:45
  • Entschuldige. Das ist vermutlich viel zu viel Code. Ich programmiere  eigentlich seit 2 Jahren nicht mehr. Ausser dem Sperrprogramm was ich wirklich schreiben müsste nur ab und zu mal eine Antwort. So wie andere halt als Entspannung ab und zu ein Kreuzworträtsel ausfüllen.

    Wenn man es nicht regelmässig tut kommt man raus. Man müsste wieder anfangen.

    So wie ich es sehe geht es darum dass es eine Basisklasse gibt. In diese verlagerst du Aufgaben von abgeleiteten Klassen damit sie nicht redundant programmiert zu werden brauchen. Dies erleichtert Änderungen und verringert die Codemenge.

    Wir haben jetzt mehrere Datentypen. Die Basisklasse und die abgeleiteten Klassen.

    Nun möchtest du in einer abgeleiteten Klasse vielleicht Properties und Methoden ansprechen die vom Typ her in der Basisklasse nicht so definiert sind. Die Basisklasse bietet aber diesen Typ nicht. Es gibt ja mehrere abgeleitete Klassen. (clsKlasse1, clsKlasse2....)

    Da besteht die Gefahr von redundanten Deklarationen. Halte das für eine Fehlerquelle. Im letzten Beispiel oben ist das auch...

    Daher noch einmal ein Beispiel in dem die Parentobjektvariable wirklich nur einmal in der Basisklasse deklariert ist und in der abgeleiteten Klasse darauf zugegriffen und so auf eine doppelte Deklaration verzichtet wird.

    Es geht bestimmt eleganter. Vielleicht hat ja jemand eine Idee. Denke mal es ist eine Grundfrage der obektorientierten Programmierung. Objektorientierte Programmierung wird heute wohl wieder langsam vergessen... Ebenso wie die Generics in Vebindung damit.

    Man will schnelle Lösungen mit Werkzeugen die Hype sind. Man kommt wieder dazu mit der Zeit desto mehr unwartbaren Code zu haben je mehr dieser wächst. Man geht so in die alten Fehler zurück. Man lässt sich blenden von der Aktualität die schnell wechselt.

    Mein grösster Wunsch wäre:
    Anstatt das Microsoft für ständig neue Technologien immer neue Werkzeuge entwickelt, das wird so weitergehen, sollte es eher dafür sogen dass die vorhandenen Programmierwerkzeuge dafür tauglich sind, d.h. darauf funktionieren.

    Das hiesse das die Begriffe von Visual Basic eine viel höhere Abstraktionsgröße bedeuten.
    Viel Aufwand für Microsoft. Der sich lohnen könnte. Weil vorhandener funktionierender Code Wert bleibt. Es ist einmal Aufwand von Microsoft gegenüber dem millionenfach vervielfachtem Aufwand des immer wieder neu schreiben müssens des immer Gleichen Konzepts um "mithalten" zu können. Bei immer schlechterer Qualität und immer magerer wirklicher innerer Funktionalität weil die Zyklen immer kürzer und der Druck immer grösser wird.

    Änderung vom 02.07.2012 um 10:20:
    Das untere ist dann gefährlich wenn Parent_Basis Public ist. Nur solange es Protected ist kann sich clsKlasse2 darauf verlassen das Parent_Basis vom Typ clsKlasse2 ist.

    Ansonsten kann bei Verwendung einer clsBasis Variable die ein Objektzeiger auf eine Instanz von clsKlasse1 ist über den Public Zugriff auf Parent dieses Property auch auf clsKlasse2 gesetzt worden sein.

    Um typsicher sich sein müsste Parent also in der abgeleiten Klasse als Objektvariable mit Dim oder Private deklariert sein und die Basisklasse diesen Zeiger bekommen. (Das wäre ein MustInherit ReadOnly Property Parent_Basis in clsBasis welches in clsKlasse1 dann den Wert der lokalen objParent Variable mit Return zurückliefert. D.h. das es für Parent keine Variablendeklaration in clsBasis gibt.) 

    Oder Parent_Basis bekommt einen Public ReadOnly Property Get und einen Protected WriteOnly Property Set. Wobei die Variablendeklaration selbst Private ist.


    Public Class Form1

      Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Dim obj1 = New clsKlasse1
        Dim obj2 = New clsKlasse2

        obj1.Parent = obj2
        obj1.ZeigeName()
        MsgBox(obj1.Parent.Test)
      End Sub
    End Class


    Public Class clsBasis
      Public Name As String = ""

      Protected Parent_Basis As clsBasis = Nothing
      ' Falls es notwendig ist auch Public.
      ' Public Parent_Basis As clsBasis = Nothing

      Public Sub ZeigeName()
        If TypeOf Me Is clsKlasse1 Then MsgBox("Me Is clsKlasse1")
        MsgBox(Me.Parent_Basis.Name)
      End Sub
    End Class


    Public Class clsKlasse1
      Inherits clsBasis

      Public Property Parent As clsKlasse2
        Get
          Return DirectCast(Parent_Basis, clsKlasse2)
        End Get

        Set(ByVal pValue As clsKlasse2)
          MyBase.Parent_Basis = pValue
        End Set
      End Property

      Public Sub New()
        Me.Name = "clsKlasse1"
      End Sub
    End Class


    Public Class clsKlasse2
      Inherits clsBasis

      Public Test As String = "Guck Guck"

      Public Sub New()
        Me.Name = "clsKlasse2"
      End Sub
    End Class




    • Bearbeitet Markus222 Montag, 2. Juli 2012 08:56
    Montag, 2. Juli 2012 07:06
  • So und mit Vererbung und Generics kombiniert sähe es dann ungefähr so aus.

    Denke das sollte der eigentliche Weg sein und das obige könnte eigentlich gelöscht werden. Aber das oben ist eben auch eine Möglichkeit.


    Public Class Form1
      Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Dim obj1 = New clsKlasse1
        Dim obj2 = New clsKlasse2

        obj1.Parent = obj2
        obj1.ZeigeName()
        MsgBox(obj1.Parent.Test)
      End Sub
    End Class


    Public MustInherit Class clsBasis
      Public Name As String = ""
    End Class


    Public MustInherit Class clsBasis_Derived(Of clsParent_TP As clsBasis)
      Inherits clsBasis

      Public Parent As clsParent_TP

      Public Sub ZeigeName()
        If Me.GetType Is GetType(clsKlasse1) Then MsgBox("Me Is clsKlasse1")
        MsgBox(Me.Parent.Name)
      End Sub
    End Class


    Public Class clsKlasse1
      Inherits clsBasis_Derived(Of clsKlasse2)

      Public Sub New()
        Me.Name = "clsKlasse1"
      End Sub
    End Class


    Public Class clsKlasse2
      Inherits clsBasis

      Public Test As String = "Guck Guck"

      Public Sub New()
        Me.Name = "clsKlasse2"
      End Sub
    End Class


    • Bearbeitet Markus222 Montag, 2. Juli 2012 07:54
    Montag, 2. Juli 2012 07:53
  • Vielen Dank,

    der entscheidende Hinweis war die Zeile  MyBase.Parent = pValue in der Eigenschaft der Klasse1 (2. Beitrag von Markus). Die Private Parent Variable benötigt man nur in der Basisklasse, die Parent-Eigenschaft in der abgeleiteten ist Shadow und alles funktioniert wunderbar.

    Auch der Hinweis StrictOn war gut. Das ist wohl guter Programmierstil, den ich verinnerlichen sollte.

    Merci Peter


    Peter

    Montag, 2. Juli 2012 20:36