VB.NET - Misusing instance variables? - vb.net

Please take a look at the code below:
Public Class A
Public person1 As Person
End Class
Public Class B
Inherits A
Public Function CheckGender() As Boolean
If person1._Gender = "M" Then
CheckGender = True
End If
End Function
End Class
Public Class C
Inherits B
Public Function CheckAge() As Boolean
If person1._Age > 30 Then
CheckAge = True
End If
End Function
End Class
Public Class D
Inherits C
Public Sub SomeMethod()
Dim list As List(Of Person) = New List(Of Person)
Dim p1 As New Person("Ian", "M", 31)
Dim p2 As New Person("Susan", "F", 20)
Dim p3 As New Person("Mark", "M", 22)
list.Add(p1)
list.Add(p2)
list.Add(p3)
For Each Person As Person In list
person1 = Person
If CheckAge() And CheckGender() Then
'Do something
End If
Next
End Sub
Public Shared Sub Main()
Dim d As New D
d.SomeMethod()
End Sub
End Class
Public Class Person
Public _Name As String
Public _Gender As String
Public _Age As String
Public Sub New(ByVal Name As String, ByVal Gender As String, ByVal Age As Integer)
_Name = Name
_Gender = Gender
_Age = Age
End Sub
End Class
c.SomeMethod loops through three persons and does two checks: b.CheckGender and c.CheckAge. CheckGender and CheckAge use an instance variable from the superclass A.
The code in the live environment loops through 100,000 records daily in a database and deletes those where CheckGender and CheckAge are both true. Is it a bad design choice to use instance variables in this scenario? I was always taught to use local variables. I would expect the Person object to be passed to CheckGender and CheckAge on each loop. Or does it really not matter?
Please note that the above code is a hypothetical example. CheckGender and CheckAge are complex functions in the actual application.

As long as CheckGender and CheckAge are not accessing any private, protected or internal member of the classes in hierarchy, and are public functions, and their logic is the same for any instance, being A, B, or C, it is a better design to have these methods in another class. Make them static if possible. You can have them accept the most general implementation of your classes (A for instance) that allows checking either the age or gender. Taken from your code, you can even pass the Person property instead of using any of the A, B and C classes.
Use of inheritance in the above case and such logic is permitted though, as long as you need to do any or all of the following:
Conform to a specific interface or base class, that A, B and C classes have to implement/extend, and that interface or base class provides the CheckGender and CheckAge methods. This can be the only solution if you pass your objects to 3rd party API, that accepts the base class/interface as an argument and internally calls the check methods.
Here is example in C#:
public static class CheckUtil
{
public static bool CheckAgeOfPerson(Person p)
{
return p.Age > 30;
}
public static bool CheckAgeOfObject(A obj)
{
// NOTE: obj.person1 must be accessible - by being either public or internal.
// If this class is in another assembly, internal is not useful
return CheckAgeOfPerson(obj.person1);
}
}
A objA = ...;
B objB = ...;
C objC = ...;
CheckUtil.CheckAgeOfObject(objA);
CheckUtil.CheckAgeOfObject(objB);
CheckUtil.CheckAgeOfObject(objC);
CheckUtil.CheckAgeOfPerson(objA.person1);
CheckUtil.CheckAgeOfPerson(objB.person1);
CheckUtil.CheckAgeOfPerson(objC.person1);
Provide specific implementation to the classes. If you have to some logic in CheckAge for instances of A, but either completely different validation for instances of B, or a combination of the existing and some new logic in C, then inheritance is your friend. Still, if that is the case, I'd prefer exposing the CheckGender and CheckAge to interface and call them via the interface. That way, inheritance is valid, but not mandatory, as long the interface is satisfied.
here is an example in C#:
public interface IGenderCheckable
{
bool CheckGender();
}
public interface IAgeCheckable
{
bool CheckAge();
}
public class A : IAgeCheckable, IGenderCheckable
{
public virtual bool CheckGender()
{
return this.person1.Gender.Equals("M");
}
public virtual bool CheckAge()
{
return this.person1.Age > 30;
}
}
public class B : A
{
public override bool CheckAge()
{
// combine custom logic with new logic
return this.person1.Age < 0 || base.CheckAge();
}
}
For complex scenarios, a combination of both approaches might be also used (of course for far more complex cases than age and gender checks):
public class A : IAgeCheckable, IGenderCheckable
{
...
}
public static class CheckUtil
{
public static bool CheckAge(IAgeCheckable obj)
{
return obj.CheckAge();
}
public static bool CheckGender(IGenderCheckable)
{
return obj.CheckGender();
}
}
About usage of instance variables vs local variables - there is a drawback in performance of using instance variables in .NET especially when they are value types. Use of local member that is int _someIntMember for example gets translated to this._someIntMember - which in turn calls the heap to get the this object, and then accesses its _someIntMember member. Having the member as a local variable, puts its value in the stack, and reads it from there without the unnecessary roundtrip trough the heap. Moreover, the stack is faster than the heap.
However, I cannot say whether too much heap usage is an abuse of it, neither a misuse of local variables when they are used too much. This depends on the performance needed, and the complexity of code. Sometimes local variables make the code more-readable, but if too many, you could easily forget what each one was (and that can be more serious issue than the negligent performance gain). So it is a matter of style and necessity.

In case you're interested in "fixing" your code to make Person a Property rather than a field, change the implementation of Class A as follows:
Public Class A
Public Property Person1 As Person
Public Overridable Function ComputeAge() As Integer
Return Person1.Age
End Function
End Class
The benefit here is you have the ability to add additional abstractions over getting and setting this property down the road if you need to. The compiler will generate a hidden private backing field for the auto property. You would still access the Person1 from any implementing classes:
Public Class B
Inherits A
Public Overrides Function ComputeAge() As Integer
Return MyBase.Person1.Age.AddYears(1)
End Function
End Class

Related

How Do I cast between 2 types that implement the same interface

I have a overlapping data objects that need to be given to at least one, possibly more, of several calculation methods to produce a common data object.
I think this is best solved by implementing both covarriance contravariance but I haven't been able to wrap my head around how what that would look like so I am open to other suggestions. In reality Animal/IAnimal and Noise have a lot of data properties so I'd like to avoid mapping them in constructors as much as possible.
Public Class Noise
Public Property Sound() As String
Public Sub Listen()
Console.WriteLine(sound)
End Sub
End Class
Public Interface IAnimal
Function Speak() As Noise()
Property Name() As String
End Interface
Public Class Dog
Implements IAnimal
Public Function Speak() As Noise() Implements IAnimal.Speak
return { new Noise() with { .Sound = "Bark" } }
End Function
Public Property Name As String Implements IAnimal.Name
End Class
Public Class Cat
Implements IAnimal
Public Function Speak() As Noise() Implements IAnimal.Speak
return { new Noise() with { .Sound = "Meow" } }
End Function
Public Property Name As String Implements IAnimal.Name
End Class
The below test produces the right output, and also works if IAnimal were an abstract base class with abstract function speak. If I understand correctly this means the covariant behavior is achieved, since it is kind of what you expect from inheritance.
Public Sub ListenToAnimalsTest()
dim spot = new Dog() With {.Name = "Spot" }
dim kitty = new Cat() With {.Name = "Kitty" }
Dim animalList As List(of IAnimal)
animalList.Add(spot)
animalList.Add(kitty)
For Each animal in animalList
Console.WriteLine(animal.Name)
animal.Speak().Listen()
Next
End Sub
The problem is I also need a CatDog that is an IAnimal
Public Class CatDog
Implements IAnimal
Public Overrides Function Speak() As Noise() Implements IAnimal.Speak
dim myself As Cat = me
dim andI As Dog = me
Return { myself.Speak(), andI.Speak()}
End Function
Public Property Name As String Implements IAnimal.Name
End Class
I'm trying to work out if I can use contravariance to allow casting Animal or IAnimal to Cat or Dog, obviously only populating the common properties.
Any thoughts or suggestions?
With regard to Decorator / Visitor Pattern I want to be able to continue whatever pattern ends up implemented by making another implementation of the parent or interface so that making the animals speak doesn't change. That means the catDog implementation of Decorator still needs to treat the IAnimal as a cat and then a dog or else I am replicating how to bark and meow in two places am I not?
Covariance and contravariance are properties of generic types (e.g. List(Of IAnimal)), which isn't really relevant to your question.
VB.NET doesn't allow true multiple inheritance, but you can create interfaces ICat and IDog that each implement IAnimal. Then you use explicit interface implementations to have your IAnimal bark or meow depending on which interface your object has been cast as.

Return object from class function

I have a namespace with a class inside it with another class inside that, i.e.
namespace MySpace
public class MainClass
public class SubClass
public x as integer
public z as integer
end class
public function Foo ()
dim y as SubClass
y.x = 5
return
end function
end class
end namespace
except the line y.x = 5 gets underlined with the tip "Variable y is used before it has been assigned a value. A null exception could result at runtime"
Basically I want to be able to have the multiple items that Foo assigns then available to whatever other code is using the MainClass class. What is the safest way to do this? If I was doing this in C I would have used a struct but apparently they are less efficient in VB?
You could make x and z shared:
Public Class SubClass
Public Shared x As Integer
Public Shared z As Integer
End Class
Or you can instantiate a class-level variable:
Public Class MainClass
Private m_objSubClass As New SubClass2
and call like so:
Public Function Foo()
'Shared
SubClass.x = 5
'Instantiated Class-Level variable
m_objSubClass.x = 5
End Function
If the Subclass needs to be accessed by other classes then expose the instantiated version through a Property instead of just a private variable (or return the instantiated version in your function).
Return m_objSubClass
Finally, if your values do not need to persist, you could simply instantiate a Subclass2 in the function:
Dim objSubClass2 As New SubClass2
objSubClass2.X = 5
Return objSubClass2

Breaking BLL (Business Logic Layer) to BLL and DAL (Data Access Layer)

Please see the code below:
Imports Microsoft.VisualBasic
Public Class PersonBLL
Private Name As String
Private Age As Integer
Dim objPersonDAL As New PersonDAL
Dim objPerson As Person
Public Sub getPersonByID()
objPerson = objPersonDAL.getPersonByID()
MsgBox(objPerson.Name)
End Sub
End Class
Public Class PersonDAL
Private Name As String
Private Age As Integer
Public Function getPersonByID() As Person
'Connect to database and get Person. Return a person object
Dim p1 As New Person
p1.Name = "Ian"
p1.Age = 30
Return p1
End Function
End Class
Public Class Person
Private _Name As String
Private _Age As Integer
Public Property Name() As String
Get
Return _Name
End Get
Set(ByVal value As String)
_Name = value
End Set
End Property
Public Property Age() As Integer
Get
Return _Age
End Get
Set(ByVal value As Integer)
_Age = value
End Set
End Property
End Class
PersonBLL calls PersonDAL and returns a Person object. Is this the correct approach? i.e. I have identified a persistent class and created a corresponding DAL class with a function for accessing the data and returning the Person object.
There is a comment that states that this question is "subjective". I agree with this. I realise that the design depends on the requirements of the project. Are there any principles documented for designing a DAL similar to SOLID (single responsibility etc) etc.
Yes, your question demonstrates a very clean way to separate the logic into layers. The PersonBLL class would be part of the business layer, the PersonDAL class would be part of the data access layer, and the Person class would be part of the data transfer objects (DTO) layer. This is a very common way to separate your layers which works well in many situations.
My only recommendations would be:
You should put each layer in their own namespaces, if not also their own class library projects.
You should not show a message box from the business layer. I assume you only did this as a means of demonstration, but just in case, I thought I should mention it. Showing a message box should be part of the UI layer. For instance, if you were calling PersonBLL.getPersonByID from a windows service or a web service, showing a message box would be entirely inappropriate.
Typically, all methods are PascalCase, not camelCase. Some people prefer to make private methods camel case, but certainly public methods shouldn't be camel case.
Consider using dependency-injection techniques (DI) to inject the data access object into the business object.
Dependency Injection
Here's an example of how to do this with DI techniques:
Public Class BusinessFactory
Public Function NewPersonBusiness() As IPersonBusiness
Return New PersonBusiness(New PersonDataAccess())
End Function
End Class
Public Class PersonBusiness
Implements IPersonBusiness
Public Sub New(personDataAccess As IPersonDataAccess)
_personDataAccess = personDataAccess
End Sub
Private _personDataAccess As IPersonDataAccess
Public Function GetPersonByID() As PersonDto Implements IPersonBusiness.GetPersonByID
Return _personDataAccess.GetPersonByID()
End Sub
End Class
Public Interface IPersonBusiness
Function GetPersonByID() As PersonDto
End Interface
Public Interface IPersonDataAccess
Function GetPersonById() As PersonDto
End Interface
Public Class PersonDto
Private _name As String
Private _age As Integer
Public Property Name() As String
Get
Return _name
End Get
Set(ByVal value As String)
_name = value
End Set
End Property
Public Property Age() As Integer
Get
Return _age
End Get
Set(ByVal value As Integer)
_age = value
End Set
End Property
End Class
Doing it this way has many advantages. You can have multiple interchangeable data access layer implementations, so it's more flexible. Also, you can inject a fake data access object when you want to unit test the business class. DI design avoids many of the traps that lead to buggy, spaghetti code.
With DI, it is typically recommended that you ask for dependency objects as an interface rather than as a concrete type (e.g. IPersonDataAccess rather than PersonDataAccess). Doing so can be a little bit of a hassle, but you get use to it quickly. Since you are often, at that point, creating one interface for every class, it's convenient to just put the interface in the same code file as the class. So, for instance, PersonBusiness.vb would contain both the PersonDataAccess class and the IPersonDataAccess interface.
There are two reasons why using interfaces, rather than classes, for your dependencies is important:
It ensures that the design is flexible. You want to be able to override every public member of the dependency type so that you can create any kind of concrete implementation. There are other ways to do this. For instance, you could skip creating the IPersonDataAcess interface by simply marking every public property and method in the PersonDataAccess class with the Overrideable modifier, but there's nothing forcing you to do that. Even if you always remembered to do so, that doesn't mean someone else working on your code would know they should do that.
DI is often tied-in with unit testing because it is the best tool available for ensuring that code is testable. When unit testing, it is particularly important that you are able to override ever member in a dependency type so you can make a "fake" object that works just the way you need it to work in order to properly perform the unit test. These "fake" objects are called mocks.
You are being more technically honest about what your dependency is. In reality, you aren't really saying that your dependency is actually an instance of the PersonDataAccess class. In actuality, your dependency is any object that happens to have that same public interface. By asking for the class, you are implying that you need a particular implementation, which is a lie. If you have designed it properly, you only care about the interface being the same, so by asking only for the interface itself, you are specifying precisely what you mean to specify :)

Covariant return types and static classes

Please have a look at the function below:
Public Function Test(ByVal i As Integer) As Animal
If i = 1 Then
Return New Dog
Else
Return New Cat
End If
End Function
A dog or a cat is returned by the function depending on whether the value of the integer is 1 or not. How is this approached if Dog and Cat are Static classes? i.e. you cannot create an instance of a static class. I have read a few webpages on the MSDN website this afternoon talking about static classes, but I have not found an answer to my specific question.
The term "static class" is a C# concept, it doesn't exist in VB.NET. So, no, this isn't possible.
It isn't possible in C# either, a static class can only derive from Object. The closest VB.NET equivalent of a static class is Module. Quite unsuitable.
You can certainly return a static instance of a class. Declare the variable in a Module or use the Shared keyword if you want to declare it inside a class.
Class Example
Private Shared theDog As Dog
Private Shared theCat As Cat
Public Shared Function Test(ByVal i As Integer) As Animal
If i = 1 Then Return theDog Else Return theCat
End Function
End Class
How is this approached if Dog and Cat are Static classes?
This isn't. You can't "return a static class" - you need to always return an object. You could use a static/shared method on a class to generate or operate on the object. For example, if you had a factory creation method on the types, you could do something like:
Public Function Test(ByVal i As Integer) As Animal
If i = 1 Then
Return Dog.Create(i)
Else
Return Cat.Create(i)
End If
End Function

Have implemented IEquatable correctly? Should I always override GetHashCode?

I saw the question posed here: Have I implemented Equals()/GetHashCode() correctly? but my c# is not as strong, and I am unfimiliar with IEquatable enough that I would like to see this in VB.NET if possible please.
My example code (The class will eventually use INotifyPropertyChanged when I get there):
Public Class Car
Implements ICloneable
Implements IEquatable(Of Car)
Public Property Make() As String
Get
Return m_Make
End Get
Set(ByVal value As String)
m_Make = value
End Set
End Property
Private m_Make As String
Public Property Model() As String
Get
Return m_Model
End Get
Set(ByVal value As String)
m_Model = value
End Set
End Property
Private m_Model As String
Public Function Clone() As Object Implements System.ICloneable.Clone
Return New Car() With { _
.Make = Me.Make, _
.Model = Me.Model _
}
End Function
Public Overloads Function Equals(ByVal other As Car) As Boolean Implements System.IEquatable(Of Car).Equals
Return other.Make = Me.Make AndAlso other.Model = Me.Model
End Function
End Class
Thanks,
You really do need to implement Overrides for the object.Equals and object.GetHashCode implementations.
Basically, implementing IEquatable(of T).Equals by itself will only work so long as the caller KNOWS to call IEquatable(of T).Equals instead of regular object.Equals.
Consider if you have an ArrayList of Cars and check if the list Contains(myCar), where myCar's Make and Model are the same as a car in the ArrayList...but the one in the ArrayList isn't actually the exact same instance. Contains would return false.
Worse yet, if you had a Hashtable or Dictionary, which uses GetHashCode to determine where to store entries, equality would never work because two cars with the same Make and Model would return different values for GetHashCode()
Basically, it comes down to you adding the following implementations to car:
Public Overrides Overloads Function Equals(obj As Object) As Boolean
Return TypeOf obj Is Car AndAlso Equals(DirectCast(obj, Car))
End Function
Public Overrides Function GetHashCode() As Int32
Dim hash As Int32 = 179 ' or something intelligent
hash = hash * 27 + Make.GetHashCode()
hash = hash * 27 + Model.GetHashCode()
Return hash
End Function
So the question I have is: why implement IEquatable at all? Why not just override Equals and GetHashCode?
Only implement IEquatable<T> for structs or sealed classes. Any legitimate implementation of IEquatable<T>.Equals(T) needs to have semantics compatible with the class's override of Object.GetHashCode(), which must in turn have semantics compatible with the class's override of Equals(Object). If a type is not sealed, the only way to ensure that derived types' implementation of IEquatable<T>.Equals(T) will be compatible with their override of Object.Equals(Object) will be to have the former method chain to the latter, effectively nullifying any advantage one might have obtained from implementing IEquatable<T> in the first place.
Implementing IEquatable<T> is often a big win for struct types (saves a boxing operation on every comparison), and a somewhat smaller win for other sealed types (saves a typecast on every comparison). Unless performance is critical, I'd probably skip it for most non-struct types, even if they're sealed.