Generics are similar to Templates found in C++, and introduces the concept of type parameters. There are, of course many differences between the two, one Generics offer a simpler approach to using type parameters without all the complexities of Templates in C++, but Generics also does not attempt to provide all the functionalities that Templates provide (thus they are not as powerful).
Utilizing Generics means you can use a generic type parameter P to write a class TheList<P> and that class can be used as TheList<int>, TheList<boolean> or even TheList<MyClass> and not have to worry about runtime conversion or illegal conversion/cast errors.
To get a better understanding of how Generics work, lets say you need to implement a Stack class, a Last-In-First-Out data structure, allowing to push items into, and pop items out of, the stack. Without the use of Generics your Stack class might look something like this
Public Class TheStackClass 'Declare our variables Private item() As Integer 'a dynamic array Private itemPointer As Integer 'Instantiate the object, setting the size of the dynamic array Public Sub New(ByVal itemSize As Integer) 'Redim the dynamic array upon instaltiation ReDim item(itemSize - 1) itemPointer = 0 End Sub '"Push" or add, an item to the stack Public Sub PushItem(ByVal i As Integer) 'First make sure the dynamic array hasnt reached its size limit If itemPointer > UBound(item) Then 'Stack is full Throw New ArgumentOutOfRangeException("The stack is currently full. Please remove an item before attempting to add a new one") Else 'Stack isnt full 'Add the item to the stack item(itemPointer) = i 'increment the itemPointer itemPointer += 1 End If End Sub '"Pop" or remove an item from the stack Pub Function PopItem() As Integer '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
This stack class accepts items of an Integer data type, if you wanted to implement this stack class for a different data type you would, as you can imagine, have to copy the class except change the data type to String (or boolean, etc). This takes code re-usability out the window, not a very efficient way to write code. You could always rewrite the stack class using an Object data type, then use late-binding, but this, of course poses a whole different problem, as seen below:
'Create a TheStackClass object and set its size 'This is based on the stack class implement Object data type then using late-binding Dim MyStack As New TheStackClass(2) MyStack.PushItem(5) MyStack.PushItem("Hello") Dim temp1, temp2 As Integer 'this will cause an uncaught run-time exception, BAD temp1 = MyStack.PopItem
The problem with this approach is the error would only be caught at run-time thus causing a nice unhanded run-time exception, now what we want.
Generics, in .Net 2.0, solves this dilemma. Using Generics you don't have to worry about changing the data type used by your stack class. Generics use the new keyword Of, which identifies the data type parameter on a class, structure, delegate, or procedure (and others of course). Lets rewrite the above class using Generics and see how they work:
Public Class TheStackClass(Of type) '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 instaltiation ReDim item(itemSize - 1) 'set the itemPointer to zero itemPointer = 0 End Sub '"Push" or add an item to the stack Public Sub PushItem(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
Notice the difference, I have used type as the placeholder for the data type that will be used when creating an object from this class. The data type isn't specified during the design of the TheStackClass class. Now lets take a look at using this class:
'Create the TheStackClass object and declare the data type to use and set its size Dim MyStack1 As New TheStackClass(Of Integer)(2) 'type is now replaced with Integer MyStack1.PushItem(1) MyStack1.PushItem(2) MyStack1.PushItem("Hello World") 'this is now a compile time error, not run-time For i As Integer = 0 To 2 Console.Write(MyStack1.PopItem) Next
See the difference, now using the wrong data type is a compile-time error and not a run-time error. Using the Of Keyword in Generics forces the compiler to check the data type being used before it can compile it (at compile-time).
Now I have a stack class I can use for any data type and I have to rewrite nothing. With Generics I can do this:
'Create the TheStackClass object and declare the data type to use and set its size Dim MyStack2 As New TheStackClass(Of String)(4) MyStack2.PushItem("</dream.in.code>") MyStack2.PushItem("rocks") MyStack2.PushItem("the iprogramming") MyStack2.PushItem("world!") MyStack2.PushItem("Hello World") 'this is now a compile time error, not run-time For i As Integer = 0 To 4 Console.Write(MyStack2.PopItem) Next
See, I had to change nothing, just replaced the placeholder type with String. Given what I've just demonstrated it's easy to see the major advantages of using Generics, they are:
- Type Safe: Using Generics forces type compliance at compile-time not run-time. This greatly reduces, if not eliminates, unhanded run-time exceptions due to data type conflicts
- Performance: Since the data type is determined at compile-time there is no type casting at run-time
- Re-usability: A class written with Generics is reusable, no need duplicating classes for different data types
This post has been edited by PsychoCoder: 03 August 2007 - 05:54 AM