Topic: About Generics
Share/Save/Bookmark
What are generics?  An easy name for parametric polymorphism that refer to classes and methods that work homogeneously on values of different types.  The code of this type of data structure remains the same; though, the data type of the parameters can change with each use.  Basically, a generic is a code template that can be used over and over with different data types.

Why use them?
   1. They're safer (more bugs are caught at compile time)
   2. They're more expressive (more invariants are expressed in type signatures)
   3. They provide more clarity (fewer explicit conversions between data types)
   4. They're more efficient (no need for run-time type checks)
   5. You'll never have to write a strongly typed collection again!

Generics allow you to specify the type to work with.                  

Topic Areas Covered in this tutorial


       How To Use Generics
       Sorting With Generics
       Sorting Directionally With Generics


NOTE: Throughout this page, you will find the use of the letter "T" to represent a data type.

In the 1.1 Framework example below, whenever you worked with a collection, you had to type check what you were adding becauseyou wold not get a compile time error.


C#  1.1 Framework VB.Net
ArrayList items = new ArrayList();
items.Add("my string");
items.Add(123);
Dim items As New ArrayList
items.Add("my string")
items.Add(123)
 







But, now if you use generics, you will get a compile time error if the type is incorrect.  This ensures that incompatible types are not added to
NOTE: VB.Net may not throw the error while compiling this, but will when executing.

C#  2.0 Framework VB.Net
List<string> items = new List<string>();
items.Add("my string");  // No Compile Error
items.Add(123);  // Compile Error
Dim items As New List(Of Integer)
items.Add("my string")
items.Add(123)









To show, how Generics can be used, let's start by creating a "User" class.
1.  Create a solution.
2.  Add a new "Class Library" Project to the Solution called "Generics".
3.  In the class properties, set the Default namespace to "Generics".
4.  Remove the Class1.cs file
5.  Add a new class called "User".
6.  Add the following methods below.


C#   VB.Net
using System;
using System.Collections.Generic;
using System.Text;

namespace Generics
{
   public class User
   {
      string userName = string.Empty;

      public User(string userName)
      {
         this.userName = userName;
      }

      public string UserName
      {
         get { return userName;  }
         set { userName = value; }
      }
   }
}
Imports System
Imports System.Collections.Generic
Imports System.Text

Public Class User

   Dim _userName As String

   Public Property UserName() As String      
      Get
         Return
_userName
      End Get      Set(ByVal value As String)
         _userName = value
      End Set

   Public Sub New(ByVal UserName As String)
      _userName = UserName
   End Sub



























Next, I'll show you how to use generics based on List    
(Remember 'T' means DataType)
1.  Right click on your solution and add a "New" project
2.  Add a new "Console Application" Project to the Solution called "ConsoleApp".
3.  In the class properties, set the Default namespace to "GenericTest".
4.  Remove the Class1.cs file
5.  Right click on References and add new reference (Navigate to Projects tab and select the Generics Project)
6.  Add a new class called "User".
7.  Add the following methods below.


NOTE:  For VB.Net, you will have to right click on the Console project and add a reference to the User Project.

C#  VB.Net
using System;
using System.Collections.Generic;
using System.Text;
using Generics;  //This is the Project above.
namespace GenericTest
{
   class program
   {
      static void Main(string[] args)
      {
         List<User> users = new List<User>();
         users.Add(new User("Dave is cool"));
         users.Add(new User("No, Dave is awesome"));
         foreach (User u in users)
            Console.WriteLine(u.UserName);
         Console.ReadLine();
       }
   }
}

Imports Generic

Module User

   Sub Main()

      Dim users As New List(Of User)

      users.Add(New User("Dave is cool"))
      users.Add(New User("Yes, he's awesome"))

      For EachAs User In users
         Console.WriteLine(u.UserName)
      Next

      Console.ReadLine()

   End Sub

End Module






























This produces the results below

Dave is Cool
No, Dave is awesome


Sorting With Generics


Next, I'll build a sorter that will allow you to sort the generic based on one of the properties within the class.
1.  Let's add another property to our class so we can choose what we want to sort by.

2.  Open up our "User" class in our Class Library and add a property called "Address"
3.  Below the userName property, type the following...

C#  VB.Net
string address = string.Empty;  Dim _address As String




4.  Next right click on the word "Address" and select "Refactor | Encapsulate Field..."
5.  This will refactor the private variable and build a property for you. (In VB.Net you will have to do this manually, unless you have a refactoring toolkit).
6.  It should look like the code below:


C#  VB.Net
public string Address
{
   get { return address;  }
   set { address = value; }
}
Public Property Address() As String
   Get
      Return
_address
   End Get
   Set
(ByVal value As String)
      _address = value
   End Set
End Property













7.  Be sure to add any new Properties to the constructor, E.g....

C#  VB.Net
public User(string UserName, string Address)
{
   this.userName = UserName;
   this.address = Address;
}
Public Sub New(ByVal Username As String, _
               ByVal Address As String)
   _userName = UserName
   _address = Address
End Sub









8.  To allow the class to be sorted based on a property, we need to first change the class signature by implementing IComparable, as follows...


C#  VB.Net
public class User : IComparable<User>
{
   ...
}
Public Class User
   Implements IComparable(Of User)







9.  Now, because we implemented IComparable, we must add a CompareTo method, as follows...      

NOTE: We could have picked any numeric or string type property to be the defualt comparer for the class.

C#  VB.Net
public int CompareTo(User other)
{
   return userName.CompareTo(other.userName);
}
Public Function CompareTo(ByVal other As User) _
   As Integer Implements _
   IComparable(Of Generic.User).CompareTo

   Return Me.UserName.CompareTo(other.UserName)
End Function












10. To test the sort capability of your Generic class, copy the following code to your Console application and run.

C#  VB.Net
using System;
using System.Collections.Generic;
using System.Text;
using Generics;  //This is the Project above.
namespace GenericTest
{
   class program
   {
      static void Main(string[] args)
      {
         List<User> users = new List<User>();
         users.Add(new User("A", "1"));
         users.Add(new User("C", "2"));
         users.Add(new User("B", "3"));
         foreach (User u in users)
            Console.Write("{0}\t{1}\n", 
                          u.UserName, u.Address);
         Console.ReadLine();
         
         users.Sort();

         foreach (User u in users)
            Console.Write("{0}\t{1}\n", 
                          u.UserName, u.Address);         
         Console.ReadLine();
       }
   }
}

Imports Generic

Module User

   Sub Main()

      Dim users As New List(Of User)

      users.Add(New User("A", "1"))
      users.Add(New User("C", "2"))
      users.Add(New User("B", "3"))

      For EachAs User In users
         Console.WriteLine(u.UserName & " " & u.Address)
      Next

      Console.WriteLine()
      users.Sort()

      For EachAs User In users
         Console.WriteLine(u.UserName & " " & u.Address)
      Next

      Console.ReadLine()

   End Sub
End Module







































This produces the results below

A        1
C        2
B        3

A        1
B        3
C        2

Sorting Directionally With Generics 

Next, I'll show you how to Sort ascending or decending on any field within the class.
1.  The first thing to add is an Enumeration within our Namespace for the direction


C#  VB.Net
public enum SortDirection
{
   ASC,
   DESC
}
Public Enum SortDirection
   ASC
   DESC
End Enum









2.  Now we will create a new Comparer class for each property that we want to sort on.  E.g....
     a.  First, we create a private direction property with a default direction of Ascending.
     b.  Then, the property for the direction is created.
     c.  Followed by the Compare method to do the sorting.


C#  VB.Net
public class UserNameCompare : IComparer<User>
{
   protected SortDirection direction = SortDirection.ASC;

   public SortDirection Direction
   {
      get { return direction;  }
      set { direction = value; }
   }

   public int Compare(User x, User y)
   {
      if (Direction == SortDirection.ASC)
         return x.UserName.CompareTo(y.UserName);
      else
         return x.UserName.CompareTo(y.UserName) * -1;
   }
}
Public Class UserNameCompare
   Implements IComparer(Of User)

   Protected _direction As SortDirection = SortDirection.ASC

   Public Property Direction() As SortDirection
      Get
         Return
_direction
      End Get
      Set
(ByVal value As SortDirection)
         _direction = value
      End Set
   End Property

   Public Function
Compare(ByVal x As Generic.User, ByVal y As Generic.User) _
      As Integer Implements _
      System.Collections.Generic.IComparer(Of Generic.User).Compare

      If _direction = SortDirection.ASC Then
         Return x.UserName.CompareTo(y.UserName)
      Else
         Return
x.UserName.CompareTo(y.UserName) * -1
      End If
   End Function
End Class







































3.  Next we'll build one for the Address property to show that it works

C#  VB.Net
public class AddressCompare : IComparer<User>
{
   protected SortDirection direction = SortDirection.ASC;

   public SortDirection Direction
   {
      get { return direction;  }
      set { direction = value; }
   }

   public int Compare(User x, User y)
   {
      if (Direction == SortDirection.ASC)
         return x.Address.CompareTo(y.Address);
      else
         return x.Address.CompareTo(y.Address) * -1;
   }
}
Public Class AddressCompare
   Implements IComparer(Of User)

   Protected _direction As SortDirection = SortDirection.ASC

   Public Property Direction() As SortDirection
     
Get
         Return
_direction
     
End Get
      Set
(ByVal value As SortDirection)
         _direction = value
     
End Set
   End Property

   Public Function
Compare(ByVal x As Generic.User, ByVal y As Generic.User) _
      As Integer Implements _
      System.Collections.Generic.IComparer(Of Generic.User).Compare

      If _direction = SortDirection.ASC Then
         Return x.Address.CompareTo(y.Address)
     
Else
         Return
x.Address.CompareTo(y.Address) * -1
     
End If
   End Function
End Class







































4.  To show how we can use directional sorting in our application, paste the following code in your Console application and give it a try.

C#  VB.Net
using System;
using System.Collections.Generic;
using System.Text;
using Generics;  //This is the Project above.
namespace GenericTest
{
   class program
   {
      static void Main(string[] args)
      {
         List<User> users = new List<User>();
         users.Add(new User("A", "1"));
         users.Add(new User("C", "2"));
         users.Add(new User("B", "3"));
         foreach (User u in users)
            Console.Write("{0}\t{1}\n", 
                          u.UserName, u.Address);

         Console.WriteLine("\n");

         UserNameCompare myNameComp = new UserNameCompare();
         myNameComp.Direction = SortDirection.DESC;
         users.Sort(myNameComp);

         foreach (User u in users)
            Console.Write("{0}\t{1}\n", 
                          u.UserName, u.Address); 
         Console.WriteLine("\n");

         AddressCompare myAddComp = new AddressCompare();
         myAddComp.Direction = SortDirection.DESC;
         users.Sort(myAddComp);

         foreach (User u in users)
            Console.Write("{0}\t{1}\n", 
                          u.UserName, u.Address);         
         Console.ReadLine();
       }
   }
}

Imports Generic

Module User

   Sub Main()

      Dim users As New List(Of User)

      users.Add(New User("A", "1"))
      users.Add(New User("C", "2"))
      users.Add(New User("B", "3"))

      For EachAs User In users
         Console.WriteLine(u.UserName & " " & u.Address)
      Next

      Console.WriteLine()
      
      Dim myNameComp As UserNameCompare = _
          New userNameCompare()
      myNameComp.Direction = SortDirection.DESC
      users.Sort(myNameComp)

      For EachAs User In users
         Console.WriteLine(u.UserName & " " & u.Address)
      Next
      Console.WriteLine()
      
      Dim myAddComp As AddressCompare = _
          New AddressCompare()
      myAddComp.Direction = SortDirection.DESC
      users.Sort(myAddComp)

      For EachAs User In users
         Console.WriteLine(u.UserName & " " & u.Address)
      Next

      Console.ReadLine()

   End Sub
End Module
































































 This produces the results below 

A        1
C        2
B        3

C        2
B        3
A        1

B        3
C        2
A        1