Go for the Generic brand…

Before .Net 2.0 the only way that you could use a generic type was to use System.Object. Although it’s been 4 years since the release of .Net 2.0 I still see developers using the System.Object way too often, which leads to unnecessary boxing/unboxing and casting. So in this article I’m going to explain how you can use Generics in your classes and methods.

What are Generics?

I entitled this article “Go for the Generic brand” because outside the world of programming the term generic means something that is not tied to a particular brand name. You may buy a bottle of shampoo without it having one of the more recognizable names printed on its label but you can still use it and expect it to clean your hair. Generics in programming works in a similar manner, you can refer to a class without it being related to a particular Type, but we can still use it in a type-safe manner.

However unlike generic brands of merchandises, that often are thought of as inferior to well known household brands, Generics in .Net are usually a good thing. I said usually a good thing because you should not look at generics as a way to replace other techniques such as method overloading, but rather as a way to replace the usage of System.Object.

A quick example

Below is a small example on what a generic class could look like.

Public Class MyGenericClass(Of T)
  Private _value As T
  Public Property Value() As T
    Get
      Return _value
    End Get
    Set(ByVal value As T)
      _value = value
    End Set
  End Property
End Class

The (Of T) part after the class name tells the compiler that this is a generic class. The T itself is merely a placeholder of a type, any type. The name T doesn’t really matter, you could just as well have typed (Of MyType) if you wanted to, however it has become a general convention to just use the capital T, unless the class expects more than one type.

In C# the same class would look like this:

public class MyGenericClass<T>
{
  private T _value;
  public T Value
  {
    get{ return _value; }
    set{ _value = value;}
  }
}

C# uses the angle brackets instead of the Of keyword as VB does, but other than that they work exactly in the same manner.

So let’s see how this class can be used. When we create a new object from the class we must provide the type we want to use.

Dim myString As New MyGenericClass(Of String)
Dim myInteger As New MyGenericClass(Of Integer)
myString.Value = "Hello World"
myInteger.Value = 123
Console.WriteLine(myString.Value)
Console.WriteLine(myInteger.Value)

Here I create two instances of the MyGenericClass one of the String type and the other of the Integer type. The Value property will then become of that particular type, so trying to do the following would create a compile error (or a runtime error if you have Option Strict set to Off) since I’m trying to assign a string value to an integer type.

myInteger.Value = "Hello"

This generic class is in no way restricted to only primitives and strings, you could use it with any type. Below I use a StringBuilder.

Dim myStringBuilder As New MyGenericClass(Of StringBuilder)
myStringBuilder.Value = New StringBuilder
myStringBuilder.Value.AppendLine("A string")
myStringBuilder.Value.AppendLine("Another string")
Console.WriteLine(myStringBuilder.Value)

Generic Methods

The whole class doesn’t have to use generics, you can use generics on a single method as well.

Public Function CreateArray(Of T)(ByVal size As Integer) As T()
  Dim array(size) As T
  Return array
End Function

Public Sub Main()
  Dim myIntArray As Integer() = CreateArray(Of Integer)(5)
  Dim myStringArray As String() = CreateArray(Of String)(5)
End Sub

This can be especially useful for extension methods, when you want to add a generic method to any type.

Type constraints

Even though the code in a generic type definition should be as type-independent as possible it is sometimes useful to add some constraints to limit the number of types that are possible. A good example is if you for example need to compare items to be able to sort them in which case they must implement the IComparable interface.

Public Class MyComparer(Of T As IComparable)
  'Insert code...
End Class

Apart from interfaces the type of constraints you can use are:

  • The type must be of a type of, or inherit from, a class.
  • The type must expose a parameterless constructor.
  • The type must be a reference type, or it must be a value type.

Let’s have a look at the first, the the type must be of, or inherit from, a specified class. Let’s say you have the following classes:

Public Class Identity
  Private _id As Integer
  Public Property ID() As Integer
    Get
      Return _id
    End Get
    Set(ByVal value As Integer)
      _id = value
    End Set
  End Property
End Class

Public Class Person
  Inherits Identity

  Private _firstName As String
  Public Property FirstName() As String
    Get
      Return _firstName
    End Get
    Set(ByVal value As String)
      _firstName = value
    End Set
  End Property

  Private _lastName As String
  Public Property LastName() As String
    Get
      Return _lastName
    End Get
    Set(ByVal value As String)
      _lastName = value
    End Set
  End Property
End Class

Public Class Company
  Inherits Identity

  Private _name As String
  Public Property Name() As String
    Get
      Return _name
    End Get
    Set(ByVal value As String)
      _name = value
    End Set
  End Property

  Private _city As String
  Public Property City() As String
    Get
      Return _city
    End Get
    Set(ByVal value As String)
      _city = value
    End Set
  End Property
  'more properties goes here...
End Class

So basically we here have an Identity class that expose an ID property and then we have a Person and a Company class that both inherit from the Identity class. Now let’s say that you want to create a collection class that only accepts objects of the Identity class or one of its descendants, it could then look something like the following.

Public Class IdentityCollection(Of T As Identity)
  Inherits List(Of T)
End Class

You can specify more than one constraint if you like, in which case you list the different constraints inside curly braces.

Public Class IdentityCollection(Of T As {Identity, IComparable})
  Inherits List(Of T)
End Class

To require an accessible parameterless constructor you would include the New keyword in the list. For a reference type include the Class keyword, and for value types you would include the Structure keyword.

Generic collections

Generics are mostly used with collections, and the .Net team have included a bunch of various generic collections for us, including list, stack, queue, and dictionary collections. They are all part of the System.Collections.Generic namespace.

In .Net 1.1 we where more or less forced to use the ArrayList collection type. However that excepted items of the System.Object type which means that casting and, if you use value types, boxing/unboxing needs to be performed. That can be very inefficient, especially in For Each loops. Using the List(Of T) we don’t have to do any of that.

Dim myList As New List(Of Person)

Conclusion

So in this article I’ve covered most of what you need to know about using generics. If you haven’t started using generics yet, I hope this article will get you started.

Have fun.

One thought on “Go for the Generic brand…”

Leave a Reply

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


*