Tuesday, July 26, 2022

Hiding a base class property

One of the problems I had when changing the look of disabled controls is that the complex controls such as DatePicker have a Background property that is ignored. They get this because they derive from the Control class but the idea of a single Background property for a complex control doesn't make sense.

I wondered if it was possible for a derived class to hide properties of its base class. There's an interesting discussion on that topic on StackOverflow, but I don't entirely agree that it's a bad idea to be able to do this.

First attempt

My first thought was to add a private overloaded property to the derived class. However if you put breakpoints on the two setters you can see that setting the property in the derived class blows right past the derived class and calls the setter on the base class. So that's a fail.

Module Module1
    Public Class BaseClass
 
        Private _X As Integer
        Public Property X As Integer
            Get
                Return _X
            End Get
            Set(value As Integer)
                _X = value
            End Set
        End Property
    End Class
 
    Public Class DerivedClass
        Inherits BaseClass
 
        Private _X As Integer
        Private Overloads Property X As Integer
            Get
                Return _X
            End Get
            Set(value As Integer)
                _X = value
            End Set
        End Property
    End Class
 
    Sub Main()
 
        Dim b As New BaseClass()
        Dim d As New DerivedClass()
 
        b.X = 4
        d.X = 4
 
        Console.ReadLine()
    End Sub
End Module

Second attempt

So how about making the derived class read-only. That would provide half the functionality we want, especially if the getter threw an exception. It does raise a build error on the setter, but only a run-time error on the getter.

Module Module1
    Public Class BaseClass
 
        Private _X As Integer
        Public Property X As Integer
            Get
                Return _X
            End Get
            Set(value As Integer)
                _X = value
            End Set
        End Property
    End Class
 
    Public Class DerivedClass
        Inherits BaseClass
        Public Overloads ReadOnly Property X As Integer
            Get
                Throw New NotImplementedException("Please stop calling me")
            End Get
        End Property
    End Class
 
    Sub Main()
 
        Dim b As New BaseClass()
        Dim d As New DerivedClass()
 
        Console.WriteLine(d.X)
        d.X = 4
        ~~~~~~~

        Console.ReadLine()
    End Sub
End Module

Third attempt

Perhaps we could use the Obsolete attribute raising an error at build time. That raises build time errors when I access the getter or the setter but the property is still listed in "Intellisense". This is the best I've been able to do so far.

Module Module1
    Public Class BaseClass
 
        Private _X As Integer
        Public Property X As Integer
            Get
                Return _X
            End Get
            Set(value As Integer)
                _X = value
            End Set
        End Property
    End Class
 
    Public Class DerivedClass
        Inherits BaseClass
        <Obsolete("Property X not supported", True)>
        Public Overloads Property X As Integer
    End Class
 
    Sub Main()
 
        Dim b As New BaseClass()
        Dim d As New DerivedClass()
 
        Console.WriteLine(d.X)
                          ~~~
        d.X = 4
        ~~~
 
        Console.ReadLine()
    End Sub
End Module


No comments:

Post a Comment