Generics in VB.NET

I am currently working on a VB.NET project that uses Generics and during my course of research into Generics I found little information on using them in VB.NET. Sure I could easily extract the principles as they were explained in C# but the flavor of the explanations were mainly geared towards C#/C++ developers which I found were foreign to most VB.NET developers. What I wanted to accomplish here is to explain Generics using a slant that VB.NET developers could understand as well as have all my code examples in VB.NET. 

  

So to start off what are Generics? To answer that question it is easier to explain what they do for you. What generics do is provide developers a way to create type safe classes and interfaces that are data type agnostic. This means that when you declare your class or interface you put a place holder for the agnostic type in the declaration and during instance creation you specify the actual type used. From this point on the compiler will enforce this contract and ensure that only types specified in your declaration are passed into your class or interface. 

  

        Dim myList As New List(Of Integer) 

        myList.Add(1) ‘everything works ok 

        myList.Add(“This is an error”) ‘this will not compile 

  

In the example above you have the new Generic list class List( Of T) that can hold any type. In this example you are making a contract saying that this List will only hold integers. Then as you can see when you try to add a string you will get a compile error. 

  

So what else can I benefit from with Generics you ask? Well how about eliminating boxing of value types. If you are not familiar with boxing here is a good explanation of it I copied from this link on MSDN http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dv_vstechart/html/vbtchperfopt.asp that talks about types as well as boxing. 

  

Boxing and Unboxing 

Boxing is the extra processing the common language runtime must do when you treat a value type as a reference type. Boxing is necessary, for example, if you declare an Integer variable and then assign it to an Object variable or pass it to a procedure that takes an Object argument. In this case, the common language runtime must box the variable to convert it to type Object. It copies the variable, embeds the copy in a newly allocated object, and stores its type information. 

If you subsequently assign the boxed variable to a variable declared as a value type, the common language runtime must unbox it, that is, copy the data from the heap instance into the value type variable. Furthermore, the boxed variable must be managed on the heap, whether or not it is ever unboxed. 

Boxing and unboxing cause very significant performance degradation. If your application frequently treats a value type variable as an object, it is better to initially declare it as a reference type. An alternative is to box the variable once, retain the boxed version as long as it is being used, and then unbox it when the value type is needed again. 

You can eliminate inadvertent boxing by setting Option Strict On. This helps you find places where you unintentionally box a value type, and it forces you to use explicit conversion, which is often more efficient than boxing. Note, however, that you cannot bypass boxing by using explicit conversion. CObj() and CType(, Object) both box the value type. 

  

To give you an example of boxing this code causes boxing. 

   

    ‘Class that can potentially cause boxing 

    Public Class PotentialBoxing 

        Private _object As Object 

        Public Property SetValueToObject() As Object 

            Get 

                Return _object 

            End Get 

            Set(ByVal value As Object) 

                _object = value 

            End Set 

        End Property 

    End Class 

  

    ‘An example of a boxing call 

    Dim myBoxingClass As New PotentialBoxing() 

    myBoxingClass.SetValueToObject = 1 

  

So to sum up the benefits that most VB.NET developers will get out of Generics (1) ability to create type safe classes and interfaces that after declaration with the desired type will be enforced by the compiler (2) a way to eliminate boxing of value types. 

  

So now with this knowledge I am going to walk you through the evolution of trying to create a type safe collection starting with how you would code it in .NET 1.0/1.1 then a potential pitfall that could occur by incorrectly coding a collection in .NET 2.0 and finally a complete type safe collection in .NET 2.0. 

  

This example caused boxing of the integer type when it was added to the collection but not when the value was passed into the Add method.   

  

   Public Class MyBoxingList 

        Inherits CollectionBase 

  

        Public Function Add(ByVal value As Integer) As Integer 

            Return List.Add(value) 

        End Function 

  

        Public Sub Remove(ByVal value As Integer) 

            List.Remove(value) 

        End Sub 

  

        Public ReadOnly Property Item(ByVal index As Integer) As Integer 

            Get 

                Return CType(List.Item(index), Integer) 

            End Get 

        End Property 

    End Class 

  

This example is much the same as above causing boxing but allows you to use any type instead of having to create a separate class for each type.  

   Public Class MyPossiblyStillBoxingGenericList(Of T) 

        Inherits CollectionBase 

  

        Public Function Add(ByVal value As T) As Integer 

            Return List.Add(value) 

        End Function 

  

        Public Sub Remove(ByVal value As T) 

            List.Remove(value) 

        End Sub 

  

        Public ReadOnly Property Item(ByVal index As Integer) As T 

            Get 

                Return CType(List.Item(index), T) 

            End Get 

        End Property 

    End Class 

  

This example allows you to create a custom class based on a collection and give you the availability to override methods if needed and will not cause boxing if you type T is of a value type. 

  

   Public Class NoBoxingList(Of T) 

        Inherits System.Collections.ObjectModel.Collection(Of T) 

        ‘you now have the opportunity to override any of the standard interfaces 

        ‘of the Collection(Of T) class if needed. 

    End Class 

  

Finally this is the easiest way to create a generic collection. 

        Dim myGenericList As New List(Of Integer) 

  

So I am sure by now you are seeing that collections are something that Generics have really helped with. The BCL has a ton of collection classes in System.Collections.Generic namespace that you can use without creating any on your own. If you are more adventurous and want to create your own custom Generic collections you are in luck, look in the System.Collections.ObjectModel namespace for generic collections that were designed to be inherited from. 

  

In my next installment on Generics I am going to cover their application outside the arena of collections and talk about generic constraints, inheritance and generics, generic methods, generic delegates and generics and reflection.

Leave a Reply

Your email address will not be published. Required fields are marked *