Is there anything particular you have to do to make a constructor function? - vb.net

So to start this off; I'm a beginner in VisualBasic.Net and my classes require me to learn it. The current subject is object constructors and constructor methods. The current exercise (it's not graded or an exam) is requiring us to make a parent class with a constructor method, and a child class with a new() that calls said function. It looks a bit like this;
Protected MustInherit Class Vehicle()
Protected ReadOnly Property Serial_No As Integer
Protected Property Mileage As Integer
Protected Property Color As String
Protected Function CreateVehicle() As Object
End Function
End Class
Public Class Car
Inherits Vehicle
Public ReadOnly Property Car_Type As String
Public Sub New()
End Sub
End Class
The thing I'm having issues with is that I'm not sure how to go about it? Can't ReadOnly properties ONLY be edited in the constructor itself, and doesn't the object need to be initialized in the constructor? Is there something particular I need to add in the CreateVehicle function?
I did ask the teacher but his answer was 'just give up on it and go do something else', which is ultimately pretty unhelpful.
Edit: (added the inheritance to the child class)
So, after being asked for clarification on what I'm trying to do; the exercise itself is not entirely about doing this, but it is the thing in the exercise that I'm struggling with. The goal is to create a Car object utilizing the constructor (New()), but the constructor must call a secondary function located inside the parent class, Vehicle.
My issue is the following : I'm not sure how to go about implementing the function inside the constructor. I know how to call methods/subs/functions and how to get returns from them, but I'm not sure on how I would go about returning a ReadOnly property's values from a secondary function. Don't readonly properties become uneditable outside of the constructor?
I could always return each value separately instead of as an object, and then set the Car object's values to be equal to the return of the function, individually. But then what's the point of calling a separate function instead of just passing everything as a parameter and doing it directly in the constructor?

This is probably what your teacher is looking for:
Public MustInherit Class Vehicle
Protected ReadOnly Property Serial_No As Integer
Protected Sub New(serialNumber As Integer)
Me.Serial_No = serialNumber
End Sub
End Class
Public Class Car
Inherits Vehicle
Public ReadOnly Property Car_Type As String
Public Sub New(serialNumber As Integer, carType As String)
MyBase.New(serialNumber)
Me.Car_Type = carType
End Sub
End Class
Both constructors take in parameters so the ReadOnly properties can be set.

Related

Access a class property only from a certain class

Suppose I have the following class:
Public Class lbMenu
Inherits Form
...
Public Sub AddItem(header As String)
Dim item As New lbMenuItem()
item.Owner = Me
item.Header = header
Controls.Add(item)
End Sub
...
End Class
and also the following class:
Public Class lbMenuItem
Inherits Control
Private _Owner As lbMenu
Public Property Owner As lbMenu
Get
Return _Owner
End Get
Set(value As lbMenu)
_Owner = value
End Set
End Property
Private _Header As String
Public Property Header As String
Get
Return _Header
End Get
Set(value As String)
_Header = value
End Set
End Property
...
End Class
As you can see, I access the Owner property of lbMenuItem from the class lbMenu.
What I want is that nobody else can access the Owner property, or maybe just to read the value of the property. I think there is no way to do that but maybe there is a solution to reach a similar situation.
Any suggestions?
Edit:
I already considered passing the owner as a parameter in the constructor, but I want that anyone can access the lbMenuItem class. Anyone can create a new instance of the class, read and write many properties, etc. The only thing I don't want is that someone can write the Owner property. Someone can create a new instance of the class without having to pass an ownerMenu parameter to the New method (he can't know what ownerMenu is for). For the same reason, lbMenuItem can't be a nested class of lbMenu.
I'm trying to get the same result as with ContextMenuStrip and ToolStripMenuItem. ToolStripMenuItem has an Owner property (which in this case has read/write access) and an OwnerItem which is read-only.
So, is there a way to make the Owner property read-only but writable from the lbMenu class?
You could just have the Owner property private or read-only if you want to allow reading its value and set it in the constructor.
Edit:
Someone can create a new instance of the class without having to pass
an ownerMenu parameter to the New method
Well, you can have two constructors, one that accepts a lbMenu parameter, and one without. So, your code would look something like this:
Public Class lbMenu
Public Sub AddItem(header As String)
Dim item As New lbMenuItem(Me)
item.Header = header
Controls.Add(item)
End Sub
End Class
Public Class lbMenuItem
' Use this instead if you don't want the property to be accessible at all.
'Private Property Owner As lbMenu
Public ReadOnly Property Owner As lbMenu
Public Property Header As String
' Allow creating an instance of the class without having to pass/set the owner.
Public Sub New()
End Sub
Public Sub New(ownerMenu As lbMenu)
Owner = ownerMenu
End Sub
End Class
One last recommendation:
Based on the names of your classes, you might consider having a parent/child relationship between them (i.e., the lbMenuItem class would be a nested class within lbMenu). This will give you the advantage of being able to access the private members of lbMenu from a lbMenuItem instance.
Hope that helps.
Addressing the new points in your edit:
ToolStripMenuItem has an Owner property ... and an OwnerItem which is read-only.
That's exactly what I proposed (i.e., to use a read-only property). Note that the OwnerItem property isn't exposed as writable to any other class.
So, is there a way to make the Owner property read-only but writable
from the lbMenu class?
No, that's not possible. A read-only property is read-only, period. You can't expose its setter to a specific class. You can, however, limit the accessibility to its setter by using the keywords Friend, Private, or Protected:
Friend Set --> will make the setter accessible (make the property writable) inside the current project and read-only outside the project.
Private Set --> will make the setter accessible from the child classes.
Protected Set --> will make the setter accessible from the derived classes.
Take a look at this question to get a better idea on how to limit the accessibility of a property setter. It's about C#, but the concept is the same.

How To Access A Shared Property Of A Class Passed As A Type Parameter

I'm trying to access a shared property of a class passed as a parameter to a type-parametrised procedure. The reason why I'm doing this is so I can embed the various API call endpoints (among other class-specific things) as properties within the class itself. I've read some similar SO posts but nothing is close enough to be sure that it isn’t possible (which I think is likely).
Below is the essence of the structure - there's some pseudo code towards the end:
MustInherit Class BaseClass
Shared Property Endpoint As String
End Class
Class Person
Inherits BaseClass
Property Age As Integer
Property Name As String
Sub New()
_Endpoint = "/GetPerson"
End Sub
End Class
Class Event
Inherits BaseClass
Property When As Date
Property Type As String
Sub New()
_Endpoint = "/GetEvent"
End Sub
End Class
Function Retrieve(T As BaseClass)(Id As String) As T
Dim oResp As HttpResponse = MakeGetCall(T.Endpoint, Id) <- T.Endpoint throws a compile error
Return Deserialize(Of T)(oResp.Content)
End Function
Dim oPerson As Person = Retrieve(Of Person)("123")
Dim oEvent As Event = Retrieve(Of Event)("123")
To my tiny mind, I would have thought that, since T’s base class is BaseClass which contains the property Endpoint, I’d be ok. But seemingly not.
I've tried a fair few things from here on SO and other places to overcome this to no avail. Yes, I realize I could perform some kind of endpoint look-up based on the type of T but the above represents a very clean solution and I’d like to get it to work if possible.
Any ideas?
Assuming you want EndPoint to be different for each subclass, you should use MustOverride instead of Shared...
MustInherit Class BaseClass
Public MustOverride Property EndPoint As String
End Class
Then return a constant in each subclass
Class Person
Inherits BaseClass
Public Overrides Property EndPoint As String
Get
Return "/Person"
End Get
You might want to declare EndPoint as ReadOnly too.
The small limitation is that you'll need an instance of the class to access EndPoint (since it isn't Shared). If you have a parameterless constructor, you could use (New Person).EndPoint where needed.

Why base classes must have default new?

I got this error
https://learn.microsoft.com/en-us/dotnet/visual-basic/misc/bc30387
And I wonder why.
What about if I never want to call parameterless new in both base and derived classes?
I can do that if I don't use inheritance. Why using inheritance means I can no longer do so?
To repeat the issue
What's the explanation? So NOT every classes need parameterless new but classes with inheritance must? That doesn't make sense.
What about if I never call derived class with parameter less constructor. I don't intent for the class to ever be constructed without parameter.
For example, say, I want to create a class without parameterless constructor. I can do that right.
But say I want to split the class into two. Parent and child class. I want BOTH not to ever have parameterless constructor.
It seems that I can't do that can I? If such is the case, can anyone please confirm it.
The link says that if you have an explicit constructor in your base class with parameters and no parameterless one than you cannot leave your derived class without constructor. Because VB.NET cannot create an implicit constructor for derived class.
If you don't write any constructors for both, it is perfectly valid.
public class Base
End Class
Public Class Derived
Inherits Base
End Class
However you cannot declare a derived class without an explicit constructor like below. Because VB.NET cannot determine how to initialize base class.
public class Base
Public sub New(ByVal Item As Integer)
End Sub
End Class
Public Class Derived
Inherits Base
End Class
To overcome this issue you can declare a default constructor on derived class which calls base class constructor with a default value.
public class Base
Public sub New(ByVal Item As Integer)
End Sub
End Class
Public Class Derived
Inherits Base
Public Sub New()
MyBase.New(5)
End Sub
End Class

Shorthand Notation on an Overrideable Property in VB.Net Not Working

In my VB.Net code, I know that when I declare a property in a class I can do so using the shorthand of, for example, Public Property Prop1 As String and .Net automatically creates a private variable _Prop1 that I can refer to within my class.
I also know that I can refer to that variable within my code using either _Prop1 or by Prop1.
Now since I've always assumed that the preferred method is to use the private variable, I've always tried to make modifications / write code within my class referring to _Prop1. This is where my problem now comes in...
I have the following situation:
Public Class MyClass_Base
Public Overridable Property Prop1 As String = "val1"
Public Sub Test()
If _Prop1 = ....
End Sub
End Class
Public Class MyClass
Inherits MyClass_Base
Public Overrides Property Prop1 As String = "val2"
End Class
Basically, I define the property as Overridable in my base class, now when I get to the Test() subroutine, _Prop1 has the value of Nothing. However Prop1 has the correct value of val2.
Programming gurus out there, what is the correct way to deal with this situation?
Do I ignore the auto-created prive variable _Prop1 and work with the public Prop1 or is there something else I should add in / not even use the shorthand notation for this and write my own getter / setter logic to ensure things change as I would like?
Thanks!!!
I think you've answered your own question. You should absolutely not rely on hidden compiler mechanics in your own code. You're referencing a variable that you did not declare and there is no guarantee in the framework that this variable will be there (or work as you might expect, as you've discovered) - it's a hack to use it, so don't.
Unless you have a very good reason not to, code in the class should reference the public property just the same as code using the class would. If you're using automatic properties then there is no difference between doing that and using the private variable. It also has the benefit that if you do, at a later time, decide to implement explicit getters and setters that your code does not break and that your new getters and setters get called.
To explore the reason you get the unexpected result, in declaring
Public Overrides Property Prop1 As String = "val2"
You end up with two different _Prop1 variables - MyClass_Base._Prop1 and MyClass._Prop1. When you then call Test(), you are calling the base class method and that will refer to the base class's _Prop1 variable which has not been set to anything since you have overriden the implicit variable, getter, and setter in the subclass.
To illustrate the point, this is similar to :
Public Class MyClass_Base
Private _Prop1 As String = "val1"
Public Sub Test()
Console.WriteLine(_Prop1)
End Sub
End Class
Public Class MySubClass
Inherits MyClass_Base
Private _Prop1 As String = "val2"
End Class
Sub Main()
Dim class1 As New MyClass_Base
Dim class2 As New MySubClass
class1.Test()
class2.Test()
End Sub
Where your output will be :
val1
val1
In the above case MyClass_Base._Prop1 is always initialized, however, while in your case, it is not. In either case, the Test() method belongs to the base class so it will always refer to its own _Prop1 and not any variables of the same name declared in subclasses.
If you do need to refer to the private field, for whatever reason, you have to be very careful about how you do it (and the implications that follow). Any method that does so would need to itself be Overridable if subclasses are intended to work with their own private variables in the same way. Not to suggest that you should continue to use implicit variables, but to demonstrate :
Public Class MyClass_Base
Public Overridable Property Prop1 As String = "val1"
Public Overridable Sub Test()
Console.WriteLine(_Prop1)
End Sub
End Class
Public Class MySubClass
Inherits MyClass_Base
Public Overrides Property Prop1 As String = "val2"
Public Overrides Sub Test()
Console.WriteLine(_Prop1)
End Sub
End Class
Here we get the "expected" result because MySubClass overrides test to reference its own private field. Better to just stick to using the property names.
From the documentation on Auto Implemented Properties:
"Attributes specified for the property do not apply to the backing field."
This is one of those areas where C# and VB.NET need to be aligned.
C# (correctly) does not allow you to access the auto implemented property backing field (without some convoluted work). I honestly don't know what you can access this in VB.
So the rule here is even though you can access the backing field of an auto implemented property you really shouldn't modify this directly (nor should you need to)
If you need to then you should use a defined backing field (with initialisation) and explicit Get and Set

Can I override an interface property?

Shell example is below. Basically, I want a client and employee to implement the SSN property from IPerson. However, I want client to have get and set (which isn't an issue), but I want employee to have get only.
Public Interface IPerson
Property SSN As String
End Interface
Public Class Client
Implements IPerson
Public Property SSN As String Implements AELName.IPerson.SSN
Get
Return _SSN
End Get
Set(value As String)
_SSN = value
End Set
End Property
End Class
Public Class Employee
Implements IPerson
Public Readonly Property SSN As String Implements AELName.IPerson.SSN
Get
Return _SSN
End Get
End Property
End Class
Employee generates an error of "'SSN' cannot implement 'SSN' because there is not matching property on interface 'IPerson'". Is there a somewhat simple way to override the SSN implementation for Employee?
You can implement an empty Set - one that doesn't update anything.
Public Class Employee
Implements IPerson
Public Readonly Property SSN As String Implements AELName.IPerson.SSN
Get
Return _SSN
End Get
Set
' Make read only for Employee
End Set
End Property
End Class
I would suggest splitting the interface into IReadablePerson and IReadWritePerson, with the latter inheriting the former. Note that the former interface is not IImmutablePerson, since the latter name would imply to consumers of the class that they should not expect any of its properties ever to change; an object which implements IReadWritePerson would not abide such expectation, but would abide the expectation that the person should be readable.
One slight annoyance with splitting the interface is that it will be necessary for the IReadWritePerson to include the modifier Shadows in the declarations of its read/write properties, and implementers of IReadWritePerson will have to provide both a read-only implementation of IReadablePerson and a read-write implementation of IReadWritePerson. In C#, a public implementation of a read-write property can automatically generate implementations for any like-named read-only, write-only, or read-write properties which are part of any interfaces the class implements, but when explicitly declaring which interface is being implemented, the style of the interface (read-only, write-only, read-write) must precisely match that of the implementation. Annoying.
The annoyance is made worse by the fact that one cannot simply declare IReadableFoo with a read-only property, IWriteOnlyFoo with a write-only property, and have IReadWriteFoo simply inherit both. If an interface implements a read-only property and a write-only property with the same name, neither property will be usable because the compiler will announce that in statements like somevariable = object.someProperty or someObject.someProperty = someVariable, it's "ambiguous" which implementation to use. Not that I can see any ambiguity--I can't see how the first could use anything but a getter, or the latter anything but a setter, but the compiler can't resolve it.
To answer your title question "Can I override an interface property" ... Absolutely. Here's an example of how to do so. You simply add the Overridable keyword to your base concrete implementation. I know that doesn't solve changing the property to ReadOnly, but I figured I'd point out that overriding a base classes concrete implementation of an interface is possible.
Module Module1
Sub Main()
Dim iEntity As IEntity = New MyEntity
iEntity.SetMessage(iEntity)
Console.WriteLine(iEntity.Message)
Console.ReadKey()
End Sub
End Module
Public Interface IEntity
Property Message As String
Sub SetMessage(entity As IEntity)
End Interface
Public Class MyEntity
Inherits BaseEntity
Public Overrides Property Message As String
Get
Return String.Format("{0}.. and overroad.", MyBase.Message)
End Get
Set(value As String)
MyBase.Message = value
End Set
End Property
Public Overrides Sub SetMessage(entity As IEntity)
Me.Message = "I was set from MyEntity."
End Sub
End Class
Public Class BaseEntity
Implements IEntity
Public Overridable Property Message As String Implements IEntity.Message
Public Overridable Sub SetMessage(entity As IEntity) Implements IEntity.SetMessage
Me.Message = "I was set from BaseEntity."
End Sub
End Class