Overriding a Sub procedure in VB.NET - vb.net

I have a main class that has a Sub procedure with no implementation. Any derived class should override and implement this procedure, so I used MustOverride in the base class.
Now, any time this procedure is called, I need to set a specific Boolean variable to True at the beginning of the procedure and set it to False at the end.
Is there a way to avoid writing these two lines of code in procedure implementation of every single derived class? Can I set this value to True in the base class, then run procedure in the derived class and then set the value back in the base class?
Thank you in advance.

When I have scenarios where a derived class needs to override a method, but I want specific things to happen before or after the overridden method code, I split it into two methods. Something like this (very simplified):
VB.NET version:
Class BaseClass
Public Sub DoWork()
' perform pre-steps '
DoWorkImpl()
' perform post-steps '
End Sub
Protected MustOverride Sub DoWorkImpl()
End Class
Derived classes will override DoWorkImpl, but the method cannot be called from the outside, since it is protected. Only DoWork can be called from the outside, ensuring that the pre- and post steps are always performed.

The way I would do this is break the work up into 2 methods. The first method would be non-virtual on the base class and would take care of setting the Boolean value. It would then call the second MustOverride method. For example
Sub Method()
MyValue = True
Try
MethodCore()
Finally
MyValue = False
End Try
End Sub
Sub MustOverride MethodCore()

Related

Is there a way to access functions (VB) in a class without making an instance of the object?

I have three classes, CarAdd, Car and EntityObject. CarAdd calls methods in EntityObject, but it doesn't have immediate access to them. Instead, it creates an object of type Car and uses it to call the methods. The problem, is that EntityObject cannot be instantiated, so is there a way for the Car class to call EntityObject's methods without an object?
I have tried to include the 'shared' functionality to the method header, but since the function implements something, I am unable to do this successfully.
'This executes when a button is pressed on the UI. _mCar is an object of type 'Car
'In class CarAdd
Public Sub BeginEdit()
If _mCar IsNot Nothing Then _mCar.BeginEdit()
End Sub
'This is the code I added to try and make this work. Since EO is nothing, 'though, the if statement never executes.
'In class Car
Private EO As EntityObject
Public Sub BeginEdit()
If EO IsNot Nothing Then
Call EO.BeginEdit()
End If
End Sub
'This is the method that I want to execute
'In class EntityObject
Public Sub BeginEdit() Implements System.ComponentModel.IEditableObject.BeginEdit
If Not _blnIsEditing Then
_blnIsEditing = True
_OriginalObject = TryCast(Me.MemberwiseClone(), EntityObject)
End If
End Sub
I had hoped that the method call would, essentially, flow through the Car class and to the EntityObject class, but this isn't what's happening. Instead, the if statement in the Car class never executes, so the method is never called.
No, not if the Sub/Function isn't Shared (BeginEdit is not Shared in EntityObject). By definition, a non-Shared Sub or Function is instance-specific and can only be used via an instance.
More about shared/non-shared class members here.

Change inheritance class at runtime

I have two class with code like this (it's just example)
class parent1
function f(param as integer) as integer
return param +2
end function
end class
'===============================
class parent2
function f(param as integer) as integer
return param *1
end function
end class
then i want to create a class inherits of one of boot based on situation at run time. maybe like this:
class child
sub new(s as string)
'it will inherits parent1
end sub
sub new(i as integer)
'it will inherits parent2
end sub
end class
Is it possible..?
.NET languages do not support multi inheritance and you cannot change it during runtime as pointed out in all comments you got.
Instead, nice "workaround" was created for this problem called Interface. Somebody call it a "hack" solution :)
For me your problem is a problem for dependency injection.
You want have child class which can change behavior during runtime.
Create abstraction of behavior, you want to change, as interface
Public Interface IBehavior
Function Calculate(value As Integer) As Integer
End Interface
Then create child class which takes behavior as constructor parameter
Public Class Child
Private ReadOnly _behavior As IBehavior
Public Sub New(behavior As IBehavior)
_behavior = behavior
End Sub
Public Sub Execute(int value)
Dim newValue As Integer = _behavior.Calculate(value)
' Do something else
End Sub
End Class
Create implementations of IBehavior you want to use during runtime
Public Class SumBehavior Implements IBehavior
Function Calculate(value As Integer) As Integer Implements IBehavior.Calculate
Return value + 2
End Function
End Class
Public Class MultiplyBehavior Implements IBehavior
Function Calculate(value As Integer) As Integer Implements IBehavior.Calculate
Return value * 2
End Function
End Class
Then during runtime you can change behavior of Child instance based on passed parameter
Dim sum As New SumBehavior()
Dim child As New Child(sum)
child.Execute(23)
Your problem is good example of "Open-Close Principle".
- Your Child class is closed for modifications -> Do something else staff in Execute method stays unmodified
- Your child class is open for modifications -> Behavior logic can be changed without touching Child class
Multiple inheritance is not possible in .Net. Now, to solve your problem
Try Dynamic Source Code Generation and Compilation. You can not do multiple inheritance but during runtime when its sure which type of class has to be inherited, dynamically create the class using CodeDom. Refer msdn link
This approach may or may not suit your need. Still if you have an scope to change the design, Use interfaces and dependency injection. (Since the function name is same in both the classes parent1 and parent2 you can take advantage of polymorphism).

Using shadowed methods/fields in an overriden method

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.

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.

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.