Mar 16 2009

The Shadow Knows! – The finer Nuisances of the VisualBasic.NET Shadows Keyword

Category: .NET | VisualBasic.NETDavid @ 15:22

I suspect that most people don’t often use the Shadows keyword.  I happened to be using it to develop a custom control because the base class I was inheriting from does not declare one of its properties as Overridable.  My control was inheriting from a StackPanel in Silverlight.  I wanted to limit the type of controls that could be placed inside of my control so I shadowed the StackPanel.Children property, which is of type List(Of UIElement), with a Children property of type List(Of CustomType). 

Initially that seemed to work.  It compiled without error or warning so I thought I was good to go.  Then the UI came up and I realized that things were not what they seemed to be.  The objects that I defined in my XAML for test were showing up, but none of the objects I added programmatically were.  Further more, the collection that was behind my custom property only contained the objects I added programmatically while the property on my StackPanel base contained the items I had defined in XAML.  WHAT?!  How is that?

The difference is in how Shadows works and how the Silverlight runtime was viewing my custom type.  When you shadow a property/method, the original property/method is hidden when your object is viewed as your custom type.  However, if your object, which is of your custom type, is cast to the type of the base class then the base class property becomes visible and is the one that gets accessed.  Let me explain with an example.

I have created three classes. Class A is the base class which B derives from A, and class C derives from class B. Like so…

Public Class A
    ReadOnly Property FirstName() As String
        Get
            Return "A"
        End Get
    End Property

    Overridable ReadOnly Property Lastname() As String
        Get
            Return "1"
        End Get
    End Property
End Class
 
Public Class B
    Inherits A

    Shadows ReadOnly Property FirstName() As String
        Get
            Return "B"
        End Get
    End Property

    Overrides ReadOnly Property Lastname() As String
        Get
            Return "2"
        End Get
    End Property
End Class
 
Public Class C
    Inherits B

    ReadOnly Property FirstName() As String
        Get
            Return "C"
        End Get
    End Property

    Overrides ReadOnly Property Lastname() As String
        Get
            Return "3"
        End Get
    End Property
End Class
 
You will notice that the Firstname property on Class A is not declared as Overridable.  This means that to replace it’s functionality I must declare it as Shadows in my derived class B.  I have purposefully left out the Shadows keyword in Class C to show that VisualBasic.NET implicitly Shadows any properties/methods in the derived class if the name matches the name of a property/method in the base class.
 
Now, here is a quick code snippet for a console app that will demonstrate this nuisance of Shadowing.
 

Sub Main() Dim cClass As New C Console.WriteLine("Typed as C: FirstName {0}, Lastname {1}", cClass.FirstName, cClass.Lastname) 'Typed as C: FirstName C, Lastname 3 Console.WriteLine("Typed as B: FirstName {0}, Lastname {1}", CType(cClass, B).FirstName, _
  CType(cClass, B).Lastname) 'Typed as B: FirstName B, Lastname 3 Console.WriteLine("Typed as A: FirstName {0}, Lastname {1}", CType(cClass, A).FirstName, _
CType(cClass, A).Lastname) 'Typed as A: FirstName A, Lastname 3 Console.ReadKey() End Sub

 

 

 

 

 

 

Notice how the value that is returned for Firstname is the value corresponding to the type by which my object is being accessed.  This correlates to my Silverlight example.  When I was adding items to my custom object programatically I was referencing it as the same type of which it is.  However, when the Silverlight run time was building the UIElement tree it was accessing my item as its base type so the items were added to the base type property, not my custom Shadows property.

So, when it comes to Shadowing, you will want to be aware that referencing your classes as the base type will expose the base types functionality and not the Shadowed functionality.

Fortunately Overrides works differently so that the functionality declared as Overrides on the most derived class will always be run and not the functionality of the base class(es). To verify this try removing the Overrides keyword from Class C.  Now the functionality that is declared as Overrides in Class B will always be accessed for the Lastname property.  You should get the following output to your console.

Typed as C: FirstName C, Lastname 3
Typed as B: FirstName B, Lastname 2
Typed as A: FirstName A, Lastname 2

 

Hopefully you have found this quick excursion into the finer points of Shadowing helpful and the next time you use Shadows you’ll know what to expect from your derived classes.

Tags: ,