Using shadowed methods/fields in an overriden method - vb.net

Suppose I had the following code:
Class NormalEmployee
Protected pay As Decimal;
Protected Shared basePay As Decimal = 300D
Protected Overridable Sub UpdatePay()
pay = basePay + .....do something......
End Sub
End Class
Class SeniorNormalEmployee
Inherits Normal Employee
Protected Shared Shadows basePay As Decimal = 500D;
Protected Overrides Sub UpdatePay()
pay = basePay + .....do something different....
End Sub
End Class
Function Main() As Integer
Dim newEmployee As NormalEmployee = New SeniorNormalEmployee()
newEmployee.CalculatePay()
return 0
End Function
I know that due to polymorphism, the CalculatePay() from my base class will be called. My question is: why does CalculatePay() use the basePay from the base class and not the derived class? The object is being stored inside a base class "container", so even though it uses the derived classes version of the method, when it goes to check the basePay shouldn't it look at the base class's version?
Furthermore, is this behavior the same when calling shadowed methods from an overrides method? Is there any way to make a field "Overridable"?
Thanks for any help!

The problem is that using the Shadows keyword makes your code use the varible of the base class, when you reference to the base class. Since you used polymorphyism and your newEmployee is defined as NormalEmployee, the basepay is the one of the base class. For more information, check here.

Related

Call baseclass property

It's rather a simple question and both will work. But I'm just wondering what the best practice is. When a child class changes a variable in the baseclass. Should it call the property or just change the underlying variable.
I'm not using the property to do something with the data. The code in the child class is the same. But what is considered the best practice OOP wise?
Sample code:
Public Class TestDirect
Protected temp As Integer
End Class
Public Class TestChldDirect
Inherits TestDirect
Public Sub New()
MyBase.temp = 1
End Sub
End Class
versus
Public Class TestProperty
Private _temp As Integer
'
Public Property temp() As Integer
Get
Return Me._temp
End Get
Set(ByVal value As Integer)
Me._temp = value
End Set
End Property
End Class
Public Class TestChldProperty
Inherits TestProperty
Public Sub New()
MyBase.temp = 1
End Sub
End Class
The second approach gives you more flexibility later on and better protects/hides your underlying implementation. For instance, in your example you might want to modify the type of temp, add some validation etc. Those changes would be more difficult in your first example as you would be affecting the classes that derive from your base class. In the second example you can make the change without affecting any derived classes.

Is there a keyword that can make a class variable readonly from outside the class but not on the inside?

Basically, the readonly keyword doesn't let me modify a field after I first create the class instance. I could use a property but in this case its just extra overhead. Is there a keyword to make a class field readonly from only outside the class?
make the field private, provide getter and setter for it.
Make the setter private.
This way the value can be seen from outside the class by the getter,but, cannot be set/written from outside the class.
this makes the property read-only from outside the class.
As others have stated, use a property. If you don't want to split the property into one Getter and one Setter then make the setter private.
Public Class Foo
Public Property Abc() As Object
Get
Return Me.m_Abc
End Get
Private Set(value As Object)
Me.m_Abc = value
End Set
End Property
Private m_Abc As Object
End Class
However: The common way is to set the access level of the field to Friend making it accessible within the same assembly, but not from outside the assembly.
Public Class Foo
Public ReadOnly Property Abc() As Object
Get
Return Me.m_Abc
End Get
End Property
Friend m_Abc As Object
End Class
No there isn't. This type is scenario is precisely why properties are provided in the first place. You get a whole lot of flexibility.
However, if you insist you want to use a read only field, you can use reflection to change the value:-
Public Class TestClass
Public ReadOnly MyNumber As Integer
Public Sub New()
'Readonly fields can only be changed this way
'in the constructor
Me.MyNumber = 900
End Sub
Public Sub ChangeNumber(ByVal num As Integer)
SetNumber(num)
End Sub
Private Sub SetNumber(ByVal num As Integer)
Dim fi = Me.GetType.GetField("MyNumber")
'Reflection can change the value of
'a read only field after construction
fi.SetValue(Me, num)
End Sub
End Class
Note that this is a very terrible thing. Reflection shouldn't be used for this sort of thing as you're going to take a performance hit. Just use properties and save yourself the trouble.

How to use classes as properties only?

I have been trying to do this for a long time but I can't find anything anywhere. I think I am not searching it as it should...
A little example:
Class MainClass
Property ExampleProperty As New ExamplePropertyClass
Private Class ExamplePropertyClass
Sub DoSomething()
End Sub
End Class
End Class
In the previous code the ExamplePropertyClass is used as an property of the MainClass.
There is always an error that says I can't expose a private class as propery.
But how is it possible to make only the property "Visible", I mean The user who is going to use the code should only use the property and not the class, how can the class be not inherited or visible?
What is property actually syntactic sugar for setter and getter.So mostly it is default public
You declare class as private. So it will be invisible outside. Then there is conflict if it be not visible then how people will know to assign and get that object without knowing its type. So that type should be public and visible
dim m as new MainClass()
m.ExampleProperty=? ' What is ExampleProperty ?int , object. So it should not be unknown
Another way you claim that you are not going to use that property outside.This way it is ok to have private class inside.
'Explicitly make property to be used only within class
Private Property ExampleProperty As ExamplePropertyClass
You do this with interfaces:
Public Interface IDoesSomething
Sub DoSomething()
End Interface
Public Class MainClass
Public Sub New()
m_example = New InternalClass
End Sub
Private m_example As IDoesSomething
Public ReadOnly Property Example() As IDoesSomething
Get
Return m_example
End Get
End Property
Private Class InternalClass
Implements IDoesSomething
Public Sub DoSomething() Implements IDoesSomething.DoSomething
End Sub
End Class
End Class

Order of initialisation

I'm playing with the following:
Public MustInherit Class TempTable
Public Sub New()
For Each f As FieldInfo In Me.GetType().GetFields
Dim l As TypedLeaf = CType(f.GetValue(Me), TypedLeaf)
Console.WriteLine(l.Name)
Next
End Sub
End Class
Public Class JMTempTable
Inherits TempTable
Public KeyIndex As New TypedLeaf(Me, "KeyIndex", OQL.Type.AUTONUMBER)
Public Debit As New TypedLeaf(Me, "Debit", OQL.Type.DECIMAL(16, 2))
Public Sub New()
MyBase.New()
End Sub
End Class
but getting Nothing for the values retrieved. The reason seems to be that the derived class' fields do not get initialised until after the base class' constructor is called... to further complicate matters, if I were to do:
Public Class JMTempTable
Inherits TempTable
Public KeyIndex As TypedLeaf
Public Debit As TypedLeaf
Public Sub New()
KeyIndex = New TypedLeaf(Me, "KeyIndex", OQL.Type.AUTONUMBER)
Debit = New TypedLeaf(Me, "Debit", OQL.Type.DECIMAL(16, 2))
MyBase.New()
End Sub
End Class
The compiler will complain that the base class constructor must be called in the first line of the derived class' constructor...
Is there a way I can delay the base class constructor from running until after the derived class' fields have been initialised?
Here's one way (perhaps the way) to do it:
Public MustInherit Class TempTable
Public Sub New()
Initialize()
For Each f As FieldInfo In Me.GetType().GetFields
Dim l As TypedLeaf = CType(f.GetValue(Me), TypedLeaf)
Console.WriteLine(l.Name)
Next
End Sub
Protected MustOverride Sub Initialize()
End Class
Public Class JMTempTable
Inherits TempTable
Public KeyIndex As TypedLeaf()
Public Debit As TypedLeaf()
Public Sub New() ' Optional block. You don't have to explicitly define a default constructor.
MyBase.New()
End Sub
Protected Overrides Sub Initialize()
KeyIndex = New TypedLeaf(Me, "KeyIndex", OQL.Type.AUTONUMBER)
Debit = New TypedLeaf(Me, "Debit", OQL.Type.DECIMAL(16, 2))
End Sub
End Class
The abstract Initialize() method forces inheritors to have a method called Initialize(). This method is implicitly called when you call MyBase.New(). That means you can now move your initialization logic out of the constructor and into the Initialize() method to get the effect you're looking for.
This is well known behavior in managed languages in general. Surprisingly I can't find it explicitly mentioned in the VB.NET Language Specification so I'll have to wing it by explaining it myself.
The CLI has direct support for field initializers but they are not strong enough to support your fields. They can only store simple data, think value types. Initializing a reference type, like your TypedLeaf class requires executing code. And code cannot be stored in a field initializer, it can only appear inside of a method.
So the VB.NET compiler works around that restriction by moving your field initialization expression to the next logical place, the class constructor. This is entirely automatic, it actually rewrites your constructor, in case you provide one yourself, injecting the new operator calls as needed.
Now there's a choice, it could move those calls before or after the base class constructor call. You already know the choice that was made, it happens after. With the justification that a field initializer should not be able to observe members of the base class that are not yet initialized. Your attempt at a workaround is actually pretty heroic compiler writing skills, it actually checks that the base constructor is called first.
Unfortunately you found a case where you are actually happier if it happened before the base constructor call. That's justifiable but unfortunately not permitted, the language designers put their foot down and declared "we only support one way to do this". Fair call, such basics need to be predictable.
The workaround is simple. Just put a Protected method in your base class, say "Initialize", and move the code you now have in the constructor to that method. In the derived class constructor just call that method. The constructor rewriting ensures that the base constructor call is first and the field initializer code is second, making the method call third. Minus 33.3 points for having to remember to make that call so add the code to throw an InvalidOperationException when you see Nothing.

Private Variable Instantiation: When Defined or Within Constructor?

I don't know if this has been asked before, but we're having a discussion about it today at my job. Should private variables (that are shared/static) be instantiated when they are dimensioned/defined, or is it a better practice to do this inside of a constructor?
For example, this seems perfectly fine to me...
Public Class IpCam
Private Const HOST As String = "http://test.com/url/example"
Private Shared _Example As New OurClass(HOST)
Public Shared ReadOnly Property Example() As OurClass
Get
Return _Example
End Get
End Property
End Class
But others are telling me that it should be done like this...
Public Class IpCam
Private Const HOST As String = "http://test.com/url/example"
Private Shared _Example As OurClass
Public Sub New()
_Example = New OurClass(HOST)
End Sub
Public Shared ReadOnly Property Example() As OurClass
Get
Return _Example
End Get
End Property
End Class
What is the difference? Is there a common consensus as to which one to use?
It's really a matter of preference. I think what's more important is consistency: if you instantiate a few variables inline, and others in a constructor, it can get harder to maintain, as it's unclear what is instantiated where.
A good idea is to keep variable declarations just above your constructor (so you don't have to jump around to find all the variable instantiations), and instantiate everything inline. For those few objects which require more complex initialization code, you can use a constructor.
I wonder if your second example is a hangover from the old VB6 days when good practise meant generally avoiding As New declarations because it wasn't optimal (auto-instantiation meant a run-time check each time) and you could never reliably test the instance for Is Nothing etc.
Member variables are initialized before the constructor; otherwise everything else is equivalent, so it's entirely up to you. I would go for what's more legible/maintainable/leads to fewer errors.
One benefit to initializing the variables inline is that you do not have to remember to put the initialization in each constructor or make sure each other constructor calls the one with the initialization. Take this code for example:
Public Class Person
Public Sub New()
_name = "asdlfkj"
End Sub
Public Sub New(ByVal age As Integer)
_age = age
End Sub
Private _name As String
Public ReadOnly Property Name As String
Get
Return _name
End Get
End Property
Private _age As Integer = 17
Public ReadOnly Property Age As Integer
Get
Return _age
End Get
End Property
End Class
Calling the first constructor will put in a default name, but calling the second will not.
Conversely, if you ever need to initialize the variable different ways for different constructors, I would definitely say to initialize in the constructor.