Page 1 of 1

Using Generics in VB.Net Make your code more efficient & reusable utilizing this new featur Rate Topic: -----

#1 PsychoCoder  Icon User is offline

  • Google.Sucks.Init(true);
  • member icon

Reputation: 1641
  • View blog
  • Posts: 19,853
  • Joined: 26-July 07

Posted 01 August 2007 - 11:30 PM

One of the additions to the .Net 2.0 Framework is the addition of Generics both in C# and in VB.Net. In this tutorial we will be discussing the user of Generics in your classes. This is Part I of a series I will be writing, introducing you to using Generics in your classes. This tutorial will show the major advantages of using Generics, and a high-level of how they work.

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 concludes Part I of this tutorial on Generics, a new feature available in the .Net 2.0 Framework. Part II Of this series will dive into utilizing constraints with Generics. If you have any questions about this tutorial or Generics in general feel free to send me a Private Message, better yet post your comments/questions here and clearing them up for one will clear up the same concerns,questions others may have. Thank you for reading, hope you enjoyed this introduction to Generics.

This post has been edited by PsychoCoder: 03 August 2007 - 05:54 AM


Is This A Good Question/Topic? 1
  • +

Replies To: Using Generics in VB.Net

#2 bms  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 1
  • Joined: 16-May 11

Posted 16 May 2011 - 08:11 AM

I'm new to Generics but it seems like what I need. I have a file watcher that monitors a folder for new files arriving. Once the file arrives, it is consumed by a class which parses it and does other things depending on the file. We have multiple files that arrive and multiple classes which consume them (1 class per file).
I'd like to write my code in a way that as new files and new classes are added we don't have to change the code and recompile.

I created an xml file which contains the list of files and which class consumes them. I use
Dim dynClass As Object
dynClass = System.Activator.CreateInstance(Type.GetType(parserClass), aParm)


to create an instance of the class and that works. The problem I have is that dynClass is an object and therefore I can't call the Process method (each class has this method as a starting point).
Would something like Generics allow me to do this properly? Any suggestions welcome.

Thanks
Was This Post Helpful? 0
  • +
  • -

#3 dk10tlx  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 1
  • Joined: 10-February 12

Posted 10 February 2012 - 02:34 PM

The answer might be "interfaces", e.g. by declaring an interface "IMyParser" that all of your different "parser classes" must implement.

Public Interface IMyParser
    Function Execute(ByVal myParam As Object) As Object
End Interface

Public Class ParserA : Implements IMyParser
    Public Function Execute(ByVal myParam As Object) As Object Implements IMyParser.Execute
        ' your code here
        Return myParam
    End Function
End Class

Public Class ParserB : Implements IMyParser
    Public Function Execute(ByVal myParam As Object) As Object Implements IMyParser.Execute
        ' your code here
        Return myParam
    End Function
End Class

Public Class MyFactory
    Public Shared Function getConcreteParser(ByVal ParserClassName As String, BindingAttributes As Reflection.BindingFlags) As IMyParser
        Return System.Activator.CreateInstance(Type.GetType(ParserClassName), BindingAttributes)
    End Function
End Class



What you can see here is a very basic example of a factory pattern using an interface to restrict the accepted types. Also by using an interface you could then directly call methods that are described by that interface.

Public Module ExampleApp
    Sub Main()
        Dim myData As Object = Nothing

        Dim pa As IMyParser = MyFactory.getConcreteParser("ParserA", Reflection.BindingFlags.CreateInstance)
        Dim pb As IMyParser = MyFactory.getConcreteParser("ParserB", Reflection.BindingFlags.CreateInstance)

        ' when you type pa. then IntelliSense will suggest Execute as method (due to the interface definition)
        pa.Execute(myData)
        pb.Execute(myData)
    End Sub
End Module



Since you introduce interfaces you are able to use even IntelliSense during coding ;-) Hope this helps.

Regards
DK
Was This Post Helpful? 0
  • +
  • -

Page 1 of 1