Shadowing in Visual Basic

Wenn zwei Programmierelemente denselben Namen aufweisen, kann eins davon das andere durch so genanntes Shadowing verbergen. In einer solchen Situation ist das Element, für das ein solches Shadowing durchgeführt wurde, nicht für Verweise verfügbar. Wenn Ihr Code den Namen dieses Elements verwendet, löst der Visual Basic-Compiler den Namen stattdessen in das Element auf, das das Shadowing durchführt.

Zweck

Der Hauptzweck von Shadowing besteht darin, die Definition Ihrer Klassenmember zu schützen. Die Basisklasse kann eine Änderung erfahren, durch die ein Element mit demselben Namen wie dem eines bereits definierten Elements erstellt wird. In diesem Fall erzwingt der Shadows-Modifizierer, dass Verweise über Ihre Klasse in den von Ihnen definierten Member aufgelöst werden, anstatt in das neue Basisklassenelement.

Typen des Shadowings

Ein Element kann das Shadowing für ein anderes Element auf zwei verschiedene Arten durchführen. Das Element, das das Shadowing durchführt, kann in einem Unterbereich des Bereichs deklariert werden, der das dem Shadowing unterzogene Element enthält. In diesem Fall wird das Shadowing über den Gültigkeitsbereich (scope) durchgeführt. Oder eine ableitende Klasse kann einen Member einer Basisklasse neu definieren. In diesem Fall erfolgt das Shadowing durch Vererbung.

Shadowing über den Gültigkeitsbereich

Es ist möglich, dass Elemente im selben Modul, in derselben Klasse oder Struktur denselben Namen, aber einen unterschiedlichen Gültigkeitsbereich haben. Wenn zwei Elemente auf diese Weise deklariert werden und der Code auf den Namen verweist, den sie gemeinsam haben, führt das Element mit dem engeren Gültigkeitsbereich ein Shadowing des anderen Elements durch (Blockbereich ist der engste).

Beispielsweise kann ein Modul eine Public-Variable mit dem Namen temp definieren, und eine Prozedur innerhalb des Moduls kann eine lokale Variable ebenfalls mit dem Namen temp deklarieren. Verweise auf temp aus der Prozedur heraus greifen auf die lokale Variable zu, während Verweise auf temp von außerhalb der Prozedur auf die Public-Variable zugreifen. In diesem Fall führt die Prozedurvariable temp ein Shadowing der Modulvariablen temp durch.

Die folgende Abbildung zeigt zwei Variablen, beide mit dem Namen temp. Die lokale Variable temp führt ein Shadowing durchführen der Membervariablen temp durch, wenn aus ihrer eigenen Prozedur p auf sie zugegriffen wird. Das Schlüsselwort MyClass umgeht jedoch das Shadowing und greift auf die Membervariable zu.

Graphic that shows shadowing through scope.

Ein Beispiel für das Shadowing über den Gültigkeitsbereich finden Sie unter Gewusst wie: Ausblenden einer Variablen mit demselben Namen wie Ihre Variable.

Shadowing durch Vererbung

Wenn eine abgeleitete Klasse ein von einer Basisklasse geerbtes Programmierelement neu definiert, führt das neu definierende Element ein Shadowing des ursprünglichen Elements durch. Sie können für jeden Typ von deklarierten Elementen und jeden Satz überladener Elemente ein Shadowing mit jedem anderen Typ durchführen. Beispielsweise kann eine Integer-Variable ein Shadowing einer Function-Prozedur durchführen. Wenn Sie ein Shadowing einer Prozedur mit einer anderen Prozedur durchführen, können Sie eine andere Parameterliste und einen anderen Rückgabetyp verwenden.

Die folgende Abbildung zeigt eine Basisklasse b und eine abgeleitete Klasse d, die von b erbt. Die Basisklasse definiert eine Prozedur mit dem Namen proc, und die abgeleitete Klasse führt ein Shadowing dieser Prozedur mit einer anderen Prozedur desselben Namens durch. Die erste Call-Anweisung greift auf die das Shadowing durchführende proc der abgeleiteten Klasse zu. Das Schlüsselwort MyBase umgeht jedoch das Shadowing und greift auf die dem Shadowing unterzogene Prozedur in der Basisklasse zu.

Graphic diagram of shadowing through inheritance

Ein Beispiel für das Shadowing durch Vererbung finden Sie unter Gewusst wie: Ausblenden einer Variablen mit demselben Namen wie Ihre Variable und Gewusst wie: Ausblenden einer geerbten Variablen.

Shadowing und Zugriffsebene

Auf das Element, das das Shadowing durchführt, kann nicht immer aus dem Code mithilfe der abgeleiteten Klasse zugegriffen werden. Beispielsweise könnte es als Private deklariert sein. In einem solchen Fall wird das Shadowing außer Kraft gesetzt, und der Compiler löst jeden Verweis auf dasselbe Element auf, das er verwendet hätte, wenn kein Shadowing vorgelegen hätte. Bei diesem Element handelt es sich um das zugängliche Element, das die wenigsten ableitenden Schritte rückwärts von der das Shadowing durchführenden Klasse entfernt ist. Wenn es sich bei dem dem Shadowing unterzogenen Element um eine Prozedur handelt, erfolgt die Auflösung in die nächstgelegene zugängliche Version mit demselben Namen, derselben Parameterliste und demselben Rückgabetyp.

Das folgende Beispiel zeigt eine Vererbungshierarchie von drei Klassen. Jede Klasse definiert eine Sub-Prozedur display, und jede abgeleitete Klasse führt ein Shadowing der display-Prozedur in ihrer Basisklasse durch.

Public Class firstClass  
    Public Sub display()  
        MsgBox("This is firstClass")  
    End Sub  
End Class  
Public Class secondClass  
    Inherits firstClass  
    Private Shadows Sub display()  
        MsgBox("This is secondClass")  
    End Sub  
End Class  
Public Class thirdClass  
    Inherits secondClass  
    Public Shadows Sub display()  
        MsgBox("This is thirdClass")  
    End Sub  
End Class  
Module callDisplay  
    Dim first As New firstClass  
    Dim second As New secondClass  
    Dim third As New thirdClass  
    Public Sub callDisplayProcedures()  
        ' The following statement displays "This is firstClass".  
        first.display()  
        ' The following statement displays "This is firstClass".  
        second.display()  
        ' The following statement displays "This is thirdClass".  
        third.display()  
    End Sub  
End Module  

Im vorherigen Beispiel führt die abgeleitete Klasse secondClass ein Shadowing von display mit einer Private-Prozedur durch. Wenn das callDisplay-Modul display in secondClass aufruft, befindet sich der aufrufende Code außerhalb von secondClass und kann daher nicht auf die private display-Prozedur zugreifen. Das Shadowing wird außer Kraft gesetzt, und der Compiler löst den Verweis auf die display-Prozedur der Basisklasse auf.

Die weiter abgeleitete thirdClass-Klasse deklariert jedoch display als Public, sodass der Code in callDisplay darauf zugreifen kann.

Shadowing und Überschreiben

Verwechseln Sie Shadowing nicht mit Überschreiben. Beide werden verwendet, wenn eine abgeleitete Klasse von einer Basisklasse erbt, und beide definieren ein deklariertes Element mit einem anderen neu. Es bestehen allerdings erhebliche Unterschiede zwischen den beiden. Einen Vergleich finden Sie unter Unterschiede zwischen Shadowing und Überschreiben.

Shadowing und Überladen

Wenn Sie ein Shadowing desselben Basisklassenelements mit mehr als einem Element in Ihrer abgeleiteten Klasse durchführen, werden die das Shadowing durchführenden Elemente zu überladenen Versionen dieses Elements. Weitere Informationen finden Sie unter Procedure Overloading.

Zugreifen auf ein dem Shadowing unterzogenes Element

Wenn Sie auf eine Element aus einer abgeleiteten Klasse zugreifen, geschieht dies normalerweise über die aktuelle Instanz dieser abgeleiteten Klasse, indem Sie den Elementnamen mit dem Schlüsselwort Me qualifizieren. Wenn Ihre abgeleitete Klasse ein Shadowing des Elements in der Basisklasse durchführt, können Sie auf das Basisklassenelement zugreifen, indem Sie es mit dem Schlüsselwort MyBase qualifizieren.

Ein Beispiel für den Zugriff auf ein dem Shadowing unterzogenes Element finden Sie unter Gewusst wie: Zugreifen auf eine von einer abgeleiteten Klasse ausgeblendete Variable.

Deklaration der Objektvariablen

Die Art, wie Sie die Objektvariable erstellen, kann sich auch darauf auswirken, ob die abgeleitete Klasse auf ein das Shadowing durchführendes Element oder auf das dem Shadowing unterzogene Element zugreift. Im folgenden Beispiel werden zwei Objekte aus einer abgeleiteten Klasse erstellt, aber ein Objekt wird als die Basisklasse und das andere als die abgeleitete Klasse deklariert.

Public Class baseCls  
    ' The following statement declares the element that is to be shadowed.  
    Public z As Integer = 100  
End Class  
Public Class dervCls  
    Inherits baseCls  
    ' The following statement declares the shadowing element.  
    Public Shadows z As String = "*"  
End Class  
Public Class useClasses  
    ' The following statement creates the object declared as the base class.  
    Dim basObj As baseCls = New dervCls()  
    ' Note that dervCls widens to its base class baseCls.  
    ' The following statement creates the object declared as the derived class.  
    Dim derObj As dervCls = New dervCls()  
    Public Sub showZ()
    ' The following statement outputs 100 (the shadowed element).  
        MsgBox("Accessed through base class: " & basObj.z)  
    ' The following statement outputs "*" (the shadowing element).  
        MsgBox("Accessed through derived class: " & derObj.z)  
    End Sub  
End Class  

Im vorherigen Beispiel wird die Variable basObj als die Basisklasse deklariert. Das Zuweisen eines dervCls-Objekts zu dieser Variablen stellt eine erweiternde Konvertierung dar und ist daher gültig. Die Basisklasse kann jedoch nicht auf die as Shadowing durchführende Version der Variablen z in der abgeleiteten Klasse zugreifen, sodass der Compiler basObj.z in den ursprünglichen Basisklassenwert auflöst.

Siehe auch