Subscribe to There and Back again, a Coders Blog        RSS Feed

VB Generics

Icon Leave Comment
As most of us know by now, Generics are allowed in Visual Basic. As well, there have been many posts and questions on this topic. I will review all of these types with what knowledge i know about Generics and how to best use them.

Generics and Why!
Recently, i stumbled upon a situation where i was coding the same methods (functions and sub's) over and over for objects (classes and structures) that were very similar. At this point, i asked myself, "How can i make these more efficient during implementation, in the event i need to expand into more objects?" The answer was to incorporate Generics and Interfaces. Although Interfaces have been beat to death on "How-To's" and "Why Not's", these components of an application, or DLL, are almost quite key to creating a template for a class, structure, or object ( i will reference all 3 of these as an object). Interfaces allow you to design a basic layout of an object so you dont manually have to code these methods, over and over again time after time. While Generics allow you to dynamically pass an unknown type as an object return or evaulation, they can be somewhat confusing. Think of Interfaces as a computer's USB-port, the connections are relatively similar, regardless of the device connecting through it. Generics are more of the Computer Chasis that can hold any type motherboard, PSU, HDD, FDD, video card, etc.

Generics use and how-to's
Through my short time of using Generics, i have found they are better used in Inheritable classes and Interfaces. Even though you can, if the need arose, use them in derived, instantiated classes/structures i would suggest against it as the user of that class/structure may not have the knowledge for what you are trying to do. That being said, i follow a KISS policy when using generics. Make your Interfaces contain the most amount of generics you will need, as long as the interface that has the most is not directly being implemented into a public scoped class. The closer you get to a public scoped class, the less amount of Generics you will want to use.

For example:
Public Interface IInterface(Of T1, T2, T3)
...some code...
End Interface
Public Interface IType(Of T1, T2)
  Inherits IInterface(Of T1, T2, IType)
...some code...
End Interface
Public MustInherit Class Type(Of T1)
  Implements IType(Of T1, Type)
..some code...
End Class
Public Class Integer
  Inherits Type(Of Integer)
...some code...
End Class

To give a real world example of some use of the Generics and how and why i used it.

Interface Example:
Public Interface IVector(Of T)
  Inherits IEquatable(Of T)

  Sub Add(ByVal v2 as T)
  Function Length() as Single
End Interface

This is my template for a Vector object. Even though there are more subs and functions available in the interface, i have given you two such methods for examples. As you can see this interface also incorporates another system interface (IEquatable(Of)), this is to allow this one single interface to extend out the IEquatable interface to the implementing objects. When you inherit a Interface into an Interface all the required implements from the inherited Interface now become part of the Interface that inherits them.

By nesting an Interface into an Interface, you allow the declaration of an object to be more clean, while still including the all the necessary implements needed for that object.

Structer declaration with Interface implement:
Public Structure Vector2
  Implements IVector(Of Vector2)

  Public Sub Add(ByVal v2 As Vector2) Implements IVector(Of Vector2).Add
    Me._x += v2._x
    Me._y += v2._y
  End Sub

  Public Function Length() As Single Implements IVector(Of Vector2).Length
    Return CSng(Sqrt(CDbl((Me._x * Me._x) + (Me._y * Me._y))))
  End Function

  Public Shadows Function Equals(ByVal other As Vector2) As Boolean Implements IEquatable(Of Vector2).Equals
    Return ((Me._x = other._x) AndAlso (Me._y = other._y))
  End Function
End Structure

As you can see i have implemented the interface and then declared the implemented methods. As well, you can see that the IEquatable interface threw in it own 2 cents, for the whole interface implementation to be successful and compliant. Now with the IVector(Of) interface developed i can develop another Structure named Vector3 and all the predefined Subs and Functions are automatically loaded (if using Visual Studio) as what is needed for the object to be compliant.

Ultimate use of this design:
Public NotInheritable Class Vector
  Public Shared Function Add(Of T As IVector(Of T))(ByVal v1 As T, ByVal v2 As T) As T
    Return v1
  End Function
  Public Shared Function Length(Of T As IVector(Of T))(ByVal v1 As T) As Single
    return v1.Length
  End Function
End Class

The above Class definition is meant as more of a lazy designers way of doing the specified methods. I know its recursive but as i have friends that like to use Shared methods instead of a instance method, this is the best way of completing that taste. What you see here is a designation of Generics at the method level. What this allows the designer to do is make sure that any type that is passed to the method, must have implemented the IVector(Of) interface. Therefore creating a consistent behavior of those objects. Since every object that inherits from the IVector(Of) interface, they will all have to specify the way the Add and Length methods work. So if i were to develop a Vector5 class similar to the Vector2 class above, i would easily program the line below, without worrying if the Shared Class Vector will operate on it.

Dim v1 as Vector5
..initialize v1 with data..
Dim v2 as Vector5
..initialize v2 with data..
Dim v3 as Vector5
v3 = Vector.Add(v1, v2)

As you can see this shared method will perform the task as if someone had performed this line of code, but without actually messing with the values of v1 directly.
Dim v1 as Vector5
..initialize v1...
Dim v2 as Vector5
..initialize v2...
Dim v3 as Vector5
v3 = v1

Now your asking yourself, what if i accidently send a Vector2 object in with a Vector5 object. The result would be a run-time TypeMismatchException. As during the coding, the environment sometimes misses the actual object being passed and verifies to make sure the objects being passed comply with the implementing of IVector(Of). I have gotten a mixed resolution on this, so it is best to check it out and catch any TypeMismatchException or just be a clean programmer about it.

As i am still learning about Generics and the power that may reside within them, this is not a definitive example but merely one programmers observation of a tool that is very useful.

0 Comments On This Entry


Trackbacks for this entry [ Trackback URL ]

There are no Trackbacks for this entry

0 user(s) viewing

0 Guests
0 member(s)
0 anonymous member(s)

Search My Blog

June 2018

1718 19 20212223

Recent Entries