When we have new
in C#, that personally I see only as a workaround to override a property that does not have a virtual/overridable declaration, in VB.NET we hav
Shadows
is for cases where your base class is Function SomeMethod() As String
and you want to have Function SomeMethod() As Integer
. Basically, to change the return type.
Overloads
is for case where your base class is Function SomeMethod() As String
and you want to add a parameter such as Function SomeMethod(ByVal value As Integer) As String
.
The Microsoft documentation indicates:
Shadowing and Overloading.
Overloads
can also be used to shadow an existing member, or set of overloaded members, in a base class. When you useOverloads
in this way, you declare the property or method with the same name and the same parameter list as the base class member, and you do not supply theShadows
keyword.
Hence, the result is the same: the child member replaces the base member. However the reasons why you may wish to achieve such result typically fall under two categories:
Having now in mind that a shadowed member typically does not exist at the time the shadowing member is defined, the reasons why by default the compiler will assume Shadows
become obvious.
The parts referring to the Shadows
keyword of this Microsoft article are also worth reading.
There are three closely related concepts; overriding, shadowing and overloading.
Overriding is when you make a new implementation for a virtual method.
Shadowing is when you make a new non-virtual implementation for a method.
Overloading is when you add a method with the same name but different parameters.
All three concepts are available both in C# and VB.
I have actually confirmed by compiling the same code with Shadows
vs Overloads
for a method with an identical name and signature in the base class and looking at the output from ildasm
for both. The only difference is the Overloads
case specifies hidebysig
.
The significance of this is best explained by Jon Skeet in this answer.
But simply it means there is only a real difference if the base class has overloads of the method being redefined:
Shadows
will cause all of those
overloads to be uncallable through
the derived class, where as Overloads
only replaces the one method.Note that this is only a language construct and not enforced by the CLI (i.e. C# and VB.NET enforce this but other languages may not).
A simple code example:
Module Module1
Sub Main()
Dim a1 As C1 = New C2
Dim a2 As New C2
a1.M1()
a2.M1()
a1.M2()
a2.M2()
a1.M3()
a2.M3()
a1.M1(1)
' Overloads on M1() allows the M1(int) to be inherited/called.
a2.M1(1)
a1.M2(1)
' Shadows on M2() does not allow M2(int) to be called.
'a2.M2(1)
a1.M3(1)
' Shadows on M3() does not allow M3(int) to be called, even though it is Overridable.
'a2.M3(1)
If Debugger.IsAttached Then _
Console.ReadLine()
End Sub
End Module
Class C1
Public Sub M1()
Console.WriteLine("C1.M1")
End Sub
Public Sub M1(ByVal i As Integer)
Console.WriteLine("C1.M1(int)")
End Sub
Public Sub M2()
Console.WriteLine("C1.M2")
End Sub
Public Sub M2(ByVal i As Integer)
Console.WriteLine("C1.M2(int)")
End Sub
Public Overridable Sub M3()
Console.WriteLine("C1.M3")
End Sub
Public Overridable Sub M3(ByVal i As Integer)
Console.WriteLine("C1.M3(int)")
End Sub
End Class
Class C2
Inherits C1
Public Overloads Sub M1()
Console.WriteLine("C2.M1")
End Sub
Public Shadows Sub M2()
Console.WriteLine("C2.M2")
End Sub
Public Shadows Sub M3()
Console.WriteLine("C2.M3")
End Sub
' At compile time the different errors below show the variation.
' (Note these errors are the same irrespective of the ordering of the C2 methods.)
' Error: 'Public Overrides Sub M1(i As Integer)' cannot override 'Public Sub M1(i As Integer)' because it is not declared 'Overridable'.
'Public Overrides Sub M1(ByVal i As Integer)
' Console.WriteLine("C2.M1(int)")
'End Sub
' Errors: sub 'M3' cannot be declared 'Overrides' because it does not override a sub in a base class.
' sub 'M3' must be declared 'Shadows' because another member with this name is declared 'Shadows'.
'Public Overrides Sub M3(ByVal i As Integer)
' Console.WriteLine("C2.M3(int)")
'End Sub
End Class
The output of the above:
C1.M1
C2.M1
C1.M2
C2.M2
C1.M3
C2.M3
C1.M1(int)
C1.M1(int)
C1.M2(int)
C1.M3(int)
The output shows the Shadows
calls are used when C2
is called directly and not when called indirectly through C1
.