What is shadowing in VB.NET

A derived type shadows the name of an inherited type member by redeclaring it. Shadowing a name does not remove the inherited type members with that name; it merely makes all of the inherited type members with that name unavailable in the derived class. The shadowing declaration may be any type of entity.

Entities than can be overloaded can choose one of two forms of shadowing. Shadowing by name is specified using the Shadows keyword. An entity that shadows by name hides everything by that name in the base class, including all overloads. Shadowing by name and signature is specified using the Overloads keyword. An entity that shadows by name and signature hides everything by that name with the same signature as the entity. For example:

Imports System

Class Base
Sub F()
End Sub

Sub F(ByVal i As Integer)
End Sub

Sub G()
End Sub

Sub G(ByVal i As Integer)
End Sub
End Class

Class Derived
Inherits Base

' Only hides F(Integer).
Overloads Sub F(ByVal i As Integer)
End Sub

' Hides G() and G(Integer).
Shadows Sub G(ByVal i As Integer)
End Sub
End Class

Module Test
Sub Main()
Dim x As Derived = New Derived()

x.F() ' Calls Base.F().
x.G() ' Error: No such method.
End Sub
End Module

A shadowing method or property that does not specify Shadows or Overloads assumes Shadows. If one member of a set of overloaded entities specifies the Shadows or Overloads keyword, they all must specify it. The Shadows and Overloads keywords cannot be specified at the same time.

It is valid to shadow the name of a type member that has been multiply-inherited through interface inheritance (and which is thereby unavailable), thus making the name available in the derived interface.

For example:

Interface ILeft
Sub F()
End Interface

Interface IRight
Sub F()
End Interface

Interface ILeftRight
Inherits ILeft, IRight
Shadows Sub F()
End Interface

Module Test
Sub G(ByVal i As ILeftRight)
i.F() ' Calls ILeftRight.F.
CType(i, ILeft).F() ' Calls ILeft.F.
CType(i, IRight).F() ' Calls IRight.F.
End Sub
End Module

Because methods are allowed to shadow inherited methods, it is possible for a class to contain several Overridable methods with the same signature. This does not present an ambiguity problem, since only the most-derived method is visible. In the following example, the C and D classes contain two Overridable methods with the same signature:

Imports System

Class A
Public Overridable Sub F()
Console.WriteLine("A.F")
End Sub
End Class

Class B
Inherits A

Public Overrides Sub F()
Console.WriteLine("B.F")
End Sub
End Class

Class C
Inherits B

Public Shadows Overridable Sub F()
Console.WriteLine("C.F")
End Sub
End Class

Class D
Inherits C

Public Overrides Sub F()
Console.WriteLine("D.F")
End Sub
End Class

Module Test
Sub Main()
Dim d As New D()
Dim a As A = d
Dim b As B = d
Dim c As C = d
a.F()
b.F()
c.F()
d.F()
End Sub
End Module

There are two Overridable methods here: one introduced by class A and the one introduced by class C. The method introduced by class C hides the method inherited from class A. Thus, the Overrides declaration in class D overrides the method introduced by class C, and it is not possible for class D to override the method introduced by class A. The example produces the output:

B.F
B.F
D.F
D.F

It is possible to invoke the hidden Overridable method by accessing an instance of class D through a less-derived type in which the method is not hidden.

It is not valid to shadow a MustOverride method, because in most cases this would make the class unusable. For example:

MustInherit Class Base
Public MustOverride Sub F()
End Class

MustInherit Class Derived
Inherits Base

Public Shadows Sub F()
End Sub
End Class

Class MoreDerived
Inherits Derived

' Error: MustOverride method Base.F is not overridden.
End Class

In this case, the class MoreDerived is required to override the MustOverride method Base.F, but because the class Derived shadows Base.F, this is not possible. There is no way to declare a valid descendent of Derived.

In contrast to shadowing a name from an outer scope, shadowing an accessible name from an inherited scope causes a warning to be reported, as in the following example:

Class Base
Public Sub F()
End Sub

Private Sub G()
End Sub
End Class

Class Derived
Inherits Base

Public Sub F() ' Warning: shadowing an inherited name.
End Sub

Public Sub G() ' No warning, Base.G is not accessible here.
End Sub
End Class

The declaration of method F in class Derived causes a warning to be reported. Shadowing an inherited name is specifically not an error, since that would preclude separate evolution of base classes. For example, the above situation might have come about because a later version of class Base introduced a method F that was not present in an earlier version of the class. Had the above situation been an error, any change made to a base class in a separately versioned class library could potentially cause derived classes to become invalid.

The warning caused by shadowing an inherited name can be eliminated through use of the Shadows or Overloads modifier:

Class Base
Public Sub F()
End Sub
End Class

Class Derived
Inherits Base

Public Shadows Sub F() 'OK.
End Sub
End Class

The Shadows modifier indicates the intention to shadow the inherited member. It is not an error to specify the Shadows or Overloads modifier if there is no type member name to shadow.

A declaration of a new member shadows an inherited member only within the scope of the new member, as in the following example:

Class Base
Public Shared Sub F()
End Sub
End Class

Class Derived
Inherits Base

Private Shared Shadows Sub F() ' Shadows Base.F in class Derived only.
End Sub
End Class

Class MoreDerived
Inherits Derived

Shared Sub G()
F() ' Invokes Base.F.
End Sub
End Class

In the example above, the declaration of method F in class Derived shadows the method F that was inherited from class Base, but since the new method F in class Derived has Private access, its scope does not extend to class MoreDerived. Thus, the call F() in MoreDerived.G is valid and will invoke Base.F. In the case of overloaded type members, the entire set of overloaded type members is treated as if they all had the most permissive access for the purposes of shadowing.

Class Base
Public Sub F()
End Sub
End Class

Class Derived
Inherits Base

Private Shadows Sub F()
End Sub

Public Shadows Sub F(ByVal i As Integer)
End Sub
End Class

Class MoreDerived
Inherits Derived

Public Sub G()
F() ' Error. No accessible member with this signature.
End Sub
End Class

In this example, even though the declaration of F() in Derived is declared with Private access, the overloaded F(Integer) is declared with Public access. Therefore, for the purpose of shadowing, the name F in Derived is treated as if it was Public, so both methods shadow F in Base.