Is this a correct/good coding practice? - vb.net

I'm struggling a bit to understand the power behind OO programming. Granted I am only slightly experienced in coding in general, I was hoping this would come a lot easier than it has. For this example I created some basic code in order to determine if this is a correct/good way of containing objects within objects. If not, would you please guide me in the correct direction.
I have 2 classes: a Boy and a Dog Class. The Boy Class contains a Dog object. The Dog object knows who its owner is.
Here is a Boy class:
Public Class Boy
Protected mName As String
Public Property Name() As String
Get
Return mName
End Get
Set(ByVal value As String)
mName = value
End Set
End Property
Protected mAge As Integer
Public Property Age() As Integer
Get
Return mAge
End Get
Set(ByVal value As Integer)
mAge = value
End Set
End Property
Protected mReturnHome As New TimeSpan(3, 15, 0)
Public Property ReturnHome() As TimeSpan
Get
Return mReturnHome
End Get
Set(ByVal value As TimeSpan)
mReturnHome = value
End Set
End Property
Protected mPet As New Dog(Me)
Public Property Pet() As Dog
Get
Return mPet
End Get
Set(ByVal value As Dog)
mPet = value
End Set
End Property
End Class
And here is a Dog class:
Public Class Dog
Private _owner As Boy
Public Sub New(ByRef Owner As Boy)
_owner = Owner
End Sub
Protected mName As String
Public Property Name() As String
Get
Return mName
End Get
Set(ByVal value As String)
mName = value
End Set
End Property
Protected mBreed As String
Public Property Breed() As String
Get
Return mBreed
End Get
Set(ByVal value As String)
mBreed = value
End Set
End Property
Protected mCanPlay As Boolean
Public Sub PlayBall()
If Now.TimeOfDay >= _owner.ReturnHome Then
mCanPlay = True
Else
mCanPlay = False
End If
End Sub
End Class
I need to be able to gain access to the Boy Class from the Dog Class because the Dog needs to be able to recognize properties specific to its owner (Boy).
Thank you.

First off, make your variables Private, not Protected. There is no need whatsoever for derived classes to access them directly.
Secondly, although this is done a lot in .NET, consider not having so many setters. Most properties shouldn’t change in an object’s lifetime. The exception are DTOs – objects which represent database entities.
Also take care only to model those aspects of an object that you actually use. In real software, most attributes of a given entity are irrelevant (e.g. hair colour of the customers in a library management software) and only a few are really needed by the software. Only model those.
Thirdly, if your Dog class needs to access specific functionality from the Boy class, the easiest recourse is to make this specific functionality Public.
Finally, don’t pass the dog’s owner via ByRef to the constructor. This works, but makes absolutely no sense. Use ByVal everywhere except where it really is required (and I argue that it’s never required, there are better solutions).

You're on the right track, although there are a few things that Boy and Dog have in common, such as Name and Age, so now you would look at those common attributes and methods and create a base class Animal from which both Boy and Dog would derive.
WRT how you tie the two together - consider that a boy could have multiple dogs, but a dog can have only one owner, so probably Boy.Dog should be Boy.Dogs (a collection) but Dog.Owner (as Boy) is absolutely fine.

Related

How to sort a custom list - SecondaryItem within PrimaryItem

Hi there have a list of custom objects that I need to be able to sort, one property within another. How do I go about doing this using .Net. Normally I would carry out all sorting requirements within the SQL that delivers the data, unfortunately in this case I don't have control over that generation of the raw data. I consequently have no experience of sorting content using .Net functions such as Linq and/or IComparable. An impression of the code elements involved are listed below:
Public Class CustomObject
Public Property PrimaryItem As String
Get
Return _primaryItem
End Get
Set(ByVal value As String)
_primaryItem = value
End Set
End Property
Public Property SecondaryItem As String
Get
Return _secondaryItem
End Get
Set(ByVal value As String)
_secondaryItem = value
End Set
End Property
End Class
Public Class CustomObjectList
Inherits List(Of CustomObject)
Public Sub New()
End Sub
End Class
In essence I want to be able to sort CustomObjectList according to SecondaryItem within PrimaryItem:
PrimaryItem1
SecondaryItem1
SecondaryItem2
etc...
PrimaryItem2
SecondaryItem1
SecondaryItem2
etc...
etc...
Hoping that some kind person will be able to give me a 'leg up' in usage of either Linq and/or iComparable.
Dim result = MyList.OrderBy(Function(x) x.PrimaryItem).ThenBy(Function(x) x.SecondaryItem)

Store and retrieve through classes - Functions, Subs and best practices

After completing a computer science degree I've landed a job as a software developer (woo!). Through university I was heavily web programming orientated sticking to Javascript and PHP (in the procedural sense). I'm now jump into object oriented programming as well in Visual Basic .NET.
I want to start on the right foot with best practices and what not so I have a simple scenario I want to know what the best way to do it is.
Let's say I have a class called 'Config.vb' which in the and on creation the 'Sub Load' reads keys from the registry.
Keys are: 'Fname', 'Lname', 'address1', 'address2', 'city', 'shoesize'.
So I want to stored these keys and their values accessible to my Main.vb.
First approach would be to declare 6 variables to stored the values so
Dim firstName = regKey("firstname").value
Dim lastName = regKey("lastname").value...
Then to have accessor methods to retrieve these values
Property ReadOnly getFirstname As String
Get
Return firstName
End Get
End Property
But writing out 6 get methods seems to be too lengthy. I could well be wrong, this is why I'm asking; is this the best way to access these variables?
Alternatively,
I was thinking maybe bunching all the keys and values in just the one Dictionary variable so it would contain all the keys with their values, then just having the one function to that accepts the key string and returns the value like:
Private Function getkey(key) As String
Return dictionary.Item(key)
End Function
This is probably how I would approach it.
Any guidance or let me know your way doing it will all help me and other to learn better!
Thanks.
As Plutonix said. Storing data in the registry isn't a good idea. Depending on how you want to access the data. If you just want to read all the data about lots of (presumably) people into your program in one go then you could check out object serialization or if you're dealing with large amounts of data check out databases.A good start with basic OOP can be found here. Its quite an old article, but should still work just fine.
As far as your data is concerned, you're better defining a new class. Like this
Friend Class Person
Dim _firstName As String
Dim _lastName As String
Public Property FirstName
Set(value)
_firstName = value
End Set
Get
Return _firstName
End Get
End Property
Public Property LastName
Set(value)
_lastName = value
End Set
Get
Return _lastName
End Get
End Property
End Class
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles Me.Load
Dim p1 As New Person
p1.FirstName = regkey("firstname")
p1.LastName = regkey("lastname")
End Sub
Of course if you're dealing with several people then you'll be better creating a list. Instead of declaring p1 as a new instance of a person, decleare the list like this
Dim peopleList As New List(Of Person)
and add people list this
Dim tempPerson As New Person
tempPerson.FirstName = regkey("firstname")
tempPerson.LastName = regkey("lastname")
peopleList.Add(tempPerson)
or
tempPerson.FirstName = "Fred"
tempPerson.LastName = "Perry"
peopleList.Add(tempPerson)
The beauty of OOP is that within a class you can declare methods(procedures) that work with the data in each instance of the class for example. say you have a property in you class called DOB - list this
Dim _DateOfBirth As Date
Public Property DOB As Date
Set(value As Date)
_DateOfBirth = value
End Set
Get
Return _DateOfBirth
End Get
End Property
You can create a function in the class like this that returns the person's age without ever having to store and update the age as time goes by. Like this:
Public Function Age() As Integer
Age = DateDiff(DateInterval.Year, _DateOfBirth, System.DateTime.Now)
Return Age
End Function
To get the age of the tempperson, just use this
Dim tempPerson As New Person
tempPerson.FirstName = "Fred"
tempPerson.LastName = "Perry"
tempPerson.DOB = CDate("8/12/1967")
MessageBox.Show("Age of the person is " & tempPerson.Age)
Gotta love OOP!

How to instantiate Class object with varying number of property values

Been working a lot with custom classes lately and I love the power you can have with them but I have come across something that I'm not able to solve and/or find anything helpful online.
I have a list of a class with properties I'm looking to only store information pulled from a database into.
Public Class CustomClass
Public _Values As String
Public _Variables As String
Public ReadOnly Property Values() As String
Get
Return _Values
End Get
End Property
Public ReadOnly Property Variables() As String
Get
Return _Variables
End Get
End Property
Sub New(ByVal values As String, ByVal variables As String)
_Values = values
_Variables = variables
End Sub
End Class
I will be iterating through some database entries, and I'm looking to store them into the appropriate property when I hit them (since I won't have them all available immediately, which is part of my problem). I want to just be able to add either the value or the variable at a time and not both of them, but since I have the sub procedure 'New' passing two arguments, it will always require passing them both. I've found the only way around this is by making them optional fields which I don't feel is the right way to solve this. Is what I'm looking to do possible with a class or would it be simpler by using a structure?
You can overload the constructor:
Friend Class Foo
' using auto-implement props:
Public Property Name As String ' creates a _Name backing field
Public Property Value as Integer
Public Sub New(newN as String, newV as Integer)
' access "hidden" backing fields if you want:
_Name = newN
_Value = newV
End Sub
Public Sub New() ' simple ctor
End Sub
Public Sub New(justName As String)
' via the prop
Name = justName
End Sub
End Class
You now have 3 ways to create the object: with full initialization, partial (name only) or as a blank object. You will often need a "simple constructor" - one with no params - for other purposes: serializers, Collection editors and the like will have no idea how to use the parameterized constructors and will require a simple one.
If rules in the App were that there was no reason for a MyFoo to ever exist unless both Name and Value being defined, implementing only the New(String, Integer) ctor enforces that rule. That is, it is first about the app rules, then about coding convenience.
Dim myFoo As New Foo ' empty one
myFoo.Name = "ziggy" ' we only know part of it
Since the default of string is nothing, you could pass nothing for the value you don't have. IE
Collection.Add(New CustomClass("My Value",Nothing))
Every type has a default, so this works with more than just strings.

OOP concept: is it possible to update the class of an instantiated object?

I am trying to write a simple program that should allow a user to save and display sets of heterogeneous, but somehow related data. For clarity sake, I will use a representative example of vehicles. The program flow is like this:
The program creates a Garage object, which is basically a class that can contain a list of vehicles objects
Then the users creates Vehicles objects, these Vehicles each have a property, lets say License Plate Nr. Once created, the Vehicle object get added to a list within the Garage object
--Later on--, the user can specify that a given Vehicle object is in fact a Car object or a Truck object (thus giving access to some specific attributes such as Number of seats for the Car, or Cargo weight for the truck)
At first sight, this might look like an OOP textbook question involving a base class and inheritance, but the problem is more subtle because at the object creation time (and until the user decides to give more info), the computer doesn't know the exact Vehicle type.
Hence my question: how would you proceed to implement this program flow? Is OOP the way to go?
Just to give an initial answer, here is what I've came up until now. There is only one Vehicle class and the various properties/values are handled by the main program (not the class) through a dictionary. However, I'm pretty sure that there must be a more elegant solution (I'm developing using VB.net):
Public Class Garage
Public GarageAdress As String
Private _ListGarageVehicles As New List(Of Vehicles)
Public Sub AddVehicle(Vehicle As Vehicles)
_ListGarageVehicles.Add(Vehicle)
End Sub
End Class
Public Class Vehicles
Public LicensePlateNumber As String
Public Enum VehicleTypes
Generic = 0
Car = 1
Truck = 2
End Enum
Public VehicleType As VehicleTypes
Public DictVehicleProperties As New Dictionary(Of String, String)
End Class
NOTE that in the example above the public/private modifiers do not necessarily reflect the original code
Let's first distinguish between the set of answers which one can ask about an object in the garage (its attributes) from the set of answers to those questions( its state).
If you are simply looking at a scenario where the set of answers changes, then a simple State Pattern applies. The attributes remain constant, and state changes. All object instantiations remain of a single type with constant attributes.
if you are looking at the more complicated situation where the available attributes for an object in the garage changes, one uses the Decorator pattern. However, I don't think this quite fits your scenario either. The Decorator pattern is for scenarios where there is a tractable number of attributes, but the number of possible combinations is potentially exponential because there is no restriction of which go with which.
The scenario that I think best handles your situation is that the object is actually undefined until identified, with only a Proxy (represented by the vehicle key) created initially, Once the object is completely identified, which it seems occurs all at once, it's full object is instantiated.
It is possible that you might want a Decorator sitting on top of the Proxy, but that might not be necessary either.
--Later on--, the user can specify that a given Vehicle object is in fact a Car object or a Truck object
You are dangerously close to asking for unrestricted downcasting as a feature. This is just not possible in managed code, the CLR provides hard guarantees that illegal downcasts are never possible. It raises the InvalidCastException when you try anyway.
Somewhat more concrete, if the original object was created as a Vehicle then there is no way that you can ever interpret or access that object as though it is a Truck. A Truck has, say, a Cargo property that Vehicle doesn't have. In fact, Vehicle doesn't even have the storage for Cargo. Re-interpreting a Vehicle as a Truck will give it a complete garbage value for Cargo. And much worse, writing the Cargo property will corrupt memory.
Unrestricted downcasting is possible in some languages, like C and C++. Particularly in C it is almost inevitable, void* is the "object class" of C. But these languages are also pretty famous for writing code that crashes at runtime. An illegal downcast is an excellent and common way to induce such a crash. The heap corruption this causes is extremely difficult to diagnose, the crash doesn't happen until much later, far removed from where the original damage was done.
You use the standard Factory pattern to create instances of a specific class that have a desired set of properties. Upcasting to the base class is always valid. Such a factory will return a reference of type Vehicle for example, even though it created a Truck object. Downcasting it later to a Truck will be valid.
Object Oriented Programming works best when you try to model realistic objects, rather than 'magical' objects that do things that don't make sense.
In the real world you can't have a car that is a vague blob, but suddenly becomes a Pickup truck. Thus it makes little sense to model your system this way, and you will run into various problems that cause you to go back to the "magic" again and again.
One can think of the compiler and the runtime environment as a sort of "pocket universe" and one can think of certain rules enforced by the compiler as "Laws of physics" that apply in that universe. In some cases you bend these laws, given certain compensations, but in general you shouldn't try to do this as it can cause huge rifts in the space-time continuum (ie, you can corrupt the internal state of the program).
Instead, I would model it this way. You can have a list of "License Plate" objects, and when you want to "create" a Pickup Truck, you use a Factory class, passing in the License Plate object and it will create a Pickup Truck that uses that license object.
Remember, that objects often contain other objects. A license plate is an object in and of itself, so why not treat it as such? Since you appear to have no real tie between the ambiguous "vehicle" and the license plate, this makes more sense.
My understanding is : You are trying to achieve in VB.net something you can actually dynamically do in JavaScript and its constructors...
I don't know if you can dynamically create Methods, Functions, Events or Properties in VB.net like :
Public Module SampleMembers
Public _PaxNum As Integer = 0
Public _CargoAmount As Integer = 0
Public Function GetPassengerNumbers() As Integer
Return _PaxNum
End Function
Public Function GetCargoAmount() As Integer
Return _CargoAmount
End Function
End Module
And then, declare in your application a basic object like :
Dim MyVehicle As Object
Later on, during runtime, dynamically add members to your vehicle object like :
Public Sub ConvertBaseVehicleToCar(ByRef CurrentVehicle As Object)
' ...
Object.AddMember(SampleMember._PaxNum, CurrentVehicle)
Object.AddMember(SampleMember.GetPassengerNumber(), CurrentVehicle)
' Where Object would have a magical Constructor Modyfier...
' That would be GREAT... of course
End Sub
But you can't do that in VB.net if I'm not mistaken
If it was just about datas...
I would use :
Public Class Vehicle
Private _PropertiesList As New SortedList(Of String, String)
Public Function AddProperty(ByVal PropertyName As String, ByVal PropertyValue As String) As Boolean
If _PropertiesList.ContainsKey(PropertyName) Then
_PropertiesList.Item(PropertyName) = PropertyValue
Return False ' Property replaced !
Else
_PropertiesList.Add(PropertyName, PropertyValue)
Return Property ' New Property added !
End If
End Function
Public Function RemoveProperty(ByVal PropertyName) As Boolean
If _PropertiesList.ContainsKey(PropertyName) Then
_PropertiesList.Remove(PropertyName)
Return True ' Property actually removed !
Else
Return False ' No property with that name !
End If
End Function
Public Function GetPropertiesList() As List(Of String)
Dim NewList As New List(Of String)
Dim CurrentProperty As String
For Each CurrentProperty In _PropertiesList.Keys
NewList.Add(CurrentProperty)
Next
Return NewList
End Function
Public Function GetProperty(ByVal PropertyName As String) As String
If _PropertiesList.ContainsKey(PropertyName) Then
Return _PropertiesList.Item(PropertyName)
Else
Return ""
' Or whatever explicit code of your choice
' like Return "N/A" or Return "#"
End If
End Function
' I would replace this latest function by
Public Property Item(ByVal PropertyName As String) As String
' ...
End Property
' ...
' And the Constructor
Public Sub New(ByVal VehicleType As String)
InitializeType(VehicleType)
End Sub
' With its default Properties like :
Private Sub InitializeType(ByVal ProposedType As String)
ProposedType = ProposedType.Trim().ToUpper()
Select Case ProposedType
Case "CAR":
Item("Type") = "CAR"
Case "TRUCK":
Item("Type") = "TRUCK"
Case "MINIVAN":
Item("Type") = "MINIVAN"
End Select
End Sub
' And add a FINAL ReadOnly Property
Public ReadOnly Property VehicleType() As String
Get
Return Item("Type")
End Get
End Property
End Class
Now, MyVehicle could be anything, a car, a truck, a plane, even PlanetEarth...
Still, I CAN'T mask or add methods, functions, properties upon runtime. My properties are all of type "String"
MyCar.Item("NumberOfWheels") = "6"
' ^^ I'll have to cast this to Integer before using it...
MessageBox.Show(SumOfWheels(MyListOfVehicles).ToString())
' Where :
Public Function SumOfWheels(ByVal ListOfVehicles As List(Of Vehicles)) As Integer
Dim CurrentVehicle As Vehicle
Dim CurrentWheels As Integer
Dim TotalWheels As Integer = 0
For Each CurrentVehicle In ListOfVehicles
If Integer.TryParse(CurrentVehicle.Item("NumberOfWheels"), CurrentWheels)
TotalWheels = TotalWheels + CurrentWheels
End If
Next
Return TotalWheels
End Function
However, I could add a sort of virtual type modyfier : The initial ReadOnly Property VehicleType()
' ...
Public Property VehicleType() As String
' The Getter is the same, but the setter is a litte bit different :
Set(ByVal NewType As String)
InitializeType(NewType) ' Simple ? No ! I'll have to edit the Method...
End Set
End Property
Private Sub InitializeType(ByVal ProposedType As String)
ProposedType = ProposedType.Trim().ToUpper()
Select Case ProposedType
Case "CAR":
Item("Type") = "CAR"
RemoveProperty("CargoHold")
Item("Drivers") = "1"
Case "TRUCK":
Item("Type") = "TRUCK"
RemoveProperty("PaxSeats") ' Well, you actually can have one.. or two..
Item("Drivers") = "1"
Case "MINIVAN":
Item("Type") = "MINIVAN"
Item("Drivers") = "1"
Case "MOTORBIKE":
Item("Type") = "MOTORBIKE"
RemoveProperty("CargoHold")
Item("Drivers") = "1"
Item("PaxSeats") = "1"
Item("NumberOfWheels") = "2"
Case "JETLINER":
Item("Type") = "JETLINER"
Item("Drivers") = "2"
Case "VINTAGEJETLINER":
Item("Type") = "VINTAGEJETLINER"
Item("Drivers") = "3"
End Select
End Sub
' ...
Anyway, I'll have to write codes for specific routines using several vehicles in my Garage. This would be members in my Garage Class. Each time I want to do specific things for a given set of vehicles, I'll had to check what type of vehicle it is and select the correct path of code to run.........
That would become very tricky if you want to have a bunch of sub models of vehicles...
' VEHICLE>MINIVAN
' VEHICLE>MINIVAN>CITROEN
' VEHICLE>MINIVAN>CITROEN>3CV
' VEHICLE>MINIVAN>CITROEN>3CV>BASIC
' VEHICLE>MINIVAN>CITROEN>3CV>COLLECTOR
' VEHICLE>MINIVAN>CITROEN>3CV>DEADHULK
But at least, you can have an usefull Function that retrives ALL vehicles with a specific property in your Garage :
Public Function GetVehicleUsingProperty(ByVal PropertyName As String, ByVal PropertyValue As String) As List(Of Vehicle)
' And a better one :
Public Function GetVehicleUsingProperty(ByVal PropertiesParam As SortedList(Of String, String)) As List(Of Vehicle)
' ... :P
Just the way I see things. Hope someone else could give a better way to implement all of this ?
I would be inclined to have a "Vehicle" base class that can be created normally (not abstract) with the basic properties that you do know. Including the VehicleType you defined set to "Generic" by default.
Create each specific type for each sub type. Defining the correct properties in a ridgid format to enforce good code.
In the base type create a function to Clone Vehicle Properties to a passed in Object. Eg.
Public sub CloneTo(byval OtherVehicle as Vehicle)
When a "Generic" vehicle needs to be more specific create the new child type, pass it to the routine to clone the existing information, and replace the old type with the new one in the Garage Collection.
You would need to evaluate the Child Type for each item in the garage collection to determine the available extended properties, but I think a good solid full tree list of children can minimize this work if all the correct levels are in place (the lower levels would be most commonly accessed and if any properties that can be are placed always at the highest level in the tree) Eg. Vehicle - Car - Sedan. PassengerCapacity for exampel is really a property of a Vehicle.

How to iterate through a property of a class in VB?

If I have a class object A, and it has properties such as a0, a1, a2... If this class has 100 properties like this (up to a99). I would like to display each of these properties, but I do not want to have 100 lines of code of calling this as following
print A.a0
print A.a1
print A.a2
...
print A.a99
The code is too inefficient, so I am wondering if there is a way to loop through these properties. Thank you.
.NET provides the ability to examine an object at runtime through a process known as reflection. The purpose of the original post was to iterate through an object's properties in an automated fashion rather than by manually coding explicit statements that displayed each property, and reflection is a process to accomplish this very thing.
For this particular purpose, looping through an object's properties at run-time, you use the GetProperties() method that is available for each Type. In your case, the Type you want to "reflect" is A, so the type-specific version of GetProperties returns a list of the instance properties for that object.
When you ask .NET to return the properties of an object, you can also specify what's called a binding flag that tells .NET which properties to return - public properties, private properties, static properties - a myriad of combinations from about twenty different values in the BindingFlags enumeration. For the purposes of this illustration, BindingFlags.Public will suffice, assuming your A0-A999 properties are declared to be public. To expose even more properties, simply combine multiple BindingFlag values with a logical "or".
So, now armed with that information, all we need to do is create a class, declare its properties, and tell Reflection to enumerate the properties for us. Assuming your Class A exists with property names A0-A999 already defined, here's how you'd enumerate ones starting with "A":
// Assuming Class "A" exists, and we have an instance of "A" held in
// a variable ActualA...
using System.Reflection
// The GetProperties method returns an array of PropertyInfo objects...
PropertyInfo[] properties = typeof(ActualA).GetProperties(BindingFlags.Public);
// Now, just iterate through them.
foreach(PropertyInfo property in properties)
{
if (property.Name.StartsWith("A")){
// use .Name, .GetValue methods/props to get interesting info from each property.
Console.WriteLine("Property {0}={1}",property.Name,
property.GetValue(ActualA,null));
}
}
There you have it. That's C# version rather than VB, but I think the general concepts should translate fairly readily. I hope that helps!
This MSDN code sample illustrates how to iterate over a class's properties using reflection:
http://msdn.microsoft.com/en-us/library/kyaxdd3x.aspx#Y900
Create a VB.Net Console application, copy and paste this code into the Module1.vb file and run it.
Module Module1
Sub Main()
For Each prop In GetType(TestClass).GetProperties()
Console.WriteLine(prop.Name)
Next
Console.ReadKey(True)
End Sub
End Module
Public Class TestClass
Private _One As String = "1"
Public Property One() As String
Get
Return _One
End Get
Set(ByVal value As String)
_One = value
End Set
End Property
Private _Two As Integer = 2
Public Property Two() As Integer
Get
Return _Two
End Get
Set(ByVal value As Integer)
_Two = value
End Set
End Property
Private _Three As Double = 3.1415927
Public Property Three() As Double
Get
Return _Three
End Get
Set(ByVal value As Double)
_Three = value
End Set
End Property
Private _Four As Decimal = 4.4D
Public Property Four() As Decimal
Get
Return _Four
End Get
Set(ByVal value As Decimal)
_Four = value
End Set
End Property
End Class