Welcome to Part II of my tutorial series on Generics in VB.Net, as you recall, in my first tutorial I gave examples of how Generics improved code re-usability, efficiency and readability of code. I gave an overview of what Generics were and how they can be used. In this tutorial I will be discussing adding Constraints in your Generics classes.
What are Constraints? Adding a Constraint to your Generics class restricts or limits the possible types that the class will accept. With a Constraint you can ensure your collection only contains or accepts
reference types. It also makes it possible to restrict your collection or class to only allow types that implement a certain interface, say IComparable(Of T) or IEnumerable(Of T). You can also specify more than one Constraint for a type, you do that like (Of T As {Automobile,IEnumerable}).
First lets create a class named
Automobile that implements IComparable, then a couple smaller classes that inherit from Automobile
NOTE:A class that implements IComparable has to have a CompareTo Function that implements IComparable.CompareToCODE
Public Class Automobile : Implements IComparable
'Lets add some variables & properties to our class
Public _automobileID As Integer
Public _color As System.Drawing.Color
Public _numDoors As Integer
Public _transType As String
Public Property Color() As System.Drawing.Color
Get
Return _color
End Get
Set(ByVal value As System.Drawing.Color)
_color = value
End Set
End Property
Public Property NumberOfDoors() As Integer
Get
Return Integer.TryParse(_numDoors,New Integer)
End Get
Set(ByVal value As Integer)
_numDoors = value
End Set
End Property
Public Property Transmission() As String
Get
Return _transType
End Get
Set(ByVal value As Integer)
_transType = value
End Set
End Property
Public ReadOnly Property AutomobileID() As Integer
Get
Return _automobileID
End Get
End Property
Public Function CompareTo(ByVal obj As Object) As Integer Implements System.IComparable.CompareTo
If Not (TypeOf obj Is Automobile) Then
Throw New ArgumentException
End If
Dim Automobile2 As Automobile = CType(obj, Automobile)
Dim cmpl As Integer = Me.AutomobileID.CompareTo(Automobile.AutomobileID)
If Not (cmpl = 0) Then
Return cmpl
End If
Return Me.AutomobileID.CompareTo(f2.AutomobileID)
End Function
End Class
Public Class HotRod : Inherits Automobile
'add your class code here
End Class
Public Class Jalopy : Inherits Automobile
'add your class code here
End Class
Public Class Truck : Inherits Automobile
'add your class code here
End Class
Now that we have our Automobile class, lets use this as a constraint in our TheStackClass class by restricting the types it can accept to the type Automobile We will add a 2 constraints on the original
type parameter as Automobile and IComparable.
CODE
Public Class TheStackClass(Of type As {Automobile,IComparable})
'declare the variables we need
Private item() As type 'create a dynamic array
private itemPointer As Integer 'Create a pointer to the item
'instantiate the class and set its size
Public Sub New(ByVal itemSize As Integer)
'Redim the dynamic array upon instantiation
ReDim item(itemSize - 1)
'set the itemPointer to zero
itemPointer = 0
End Sub
'"Push" or add an item to the stack
Public Sub PushItem(Of Automobile)(ByVal i As type)
'first make sure the stack isnt full
If itemPointer > UBound(item) Then
Throw New ArgumentOutOfRangeException("The stack is currently full. Please remove an item before attempting to add a new one")
Else 'stack isnt full
item(itemPointer) = i
itemPointer +=1
End If
End Sub
'"Pop" or remove an item from the stack
Public Function PopItem() As type
'decrement the itemPointer
itemPointer -= 1
'check to see if the stack is empty
If itemPointer < 0 Then 'stack is currently empty
Throw New ArgumentOutOfRangeException("The stack is currently empty.You cannot remove an item from an empty stack")
End If
'return the itemPointer value
Return item(itemPointer)
End Function
End Class
As you notice, in the original class it was Public Class TheStackClass(Of Type), but adding the constraint Public Class TheStackTrace(Of type {Automobile,IComparable}) we have added a constraint that the only types this will now accept are Automobile and IComparable.
Also, the PushItem method we added a Constraint to that as well, changing the definition to Public Sub PushItem(Of Automobile)(ByVal i As type), yes you can add Constraints to methods within the Generic Class as well.
If we tried to now call this class the way we did originally
CODE
Dim MyStack As New TheStackClass(Of String)(4)
THis would cause a compile time error, we now have to call it like this
CODE
Dim MyStack As New TheStackClass(Of HotRod)(3)
Dim MyStack As New TheStackClass(Of Jalopy)(4)
Dim MyStack As New TheStackClass(Of Truck)(2)
'and so on.....
Notice we use the Type HotRod, this is one of the classes we have that inherits the Automobile class. Using Constraints in your Generic Type is definitely an improved way of writing code, it also makes it more efficient, easier to read and type safe.
This is a high-level overview of adding a constraint to your Generic class, though there are many more things you can do with Generics, many more constraints you can work with, Generics in VB.Net do have many more limitations than its counterpart C#. Some of the limitations are:
- Since Generics without constraints are viewed as System.Object types, you cannot access type members not available to System.Object
- You cannot use arithmetic operations or nested class (though constraints can be added to soften this up a little)
- You cannot access static members or nested classes without explicit casting (Ctype(obj,TheTypeYouWant))
- You cannot use arithmetic operations unless your base class supports them (your base class is your constraint)
- You cannot use Generics as type arguments
So that is adding Constraints to your Generics Class, if you have questions or comments you can send me a PM and I will answer them. Better yet, post your questions here and I can answer them for you, and anyone else who may have the same question. Thank you for reading.
Happy Coding!