Last month, we discussed the new features of Whidbey, the upcoming .NET Framework version. In this article, we will
understand how the concept of Generics, or template based development for .NET, works.
Understanding the Why
If you have been a developer who has been involved in template-based development, like ATL and STL, and has recently shifted to .NET based development, you would have probably missed writing generic code. For those who are not clear about the notion of generic code or templates, as they are better known as, the following example will help clear this concept.
Assume you have to write code to implement a Queue data structure that can be used to maintain a queue of integers, floats, longs and other data types as applicable. Consequently, the conventional approach in a non-template based development environment would be to code the Queue implementation for all the required data-types.
Clearly, this involves a lot of development time, not to mention the code duplicacy that happens. Apart from this, when the final binary is produced, the file size is also bloated.
However, in template-based development, you would write a generic code, which at the time of writing will not specify the particular data type. The data type will be specified during the instantiation of the class, or the invocation of the method. Such classes or methods that use the notion of generic code are termed as template class or template methods in C++.
In Whidbey¸ Microsoft is adding support to write such generic classes and methods. This feature, called Generics, uses various .NET grammars. By the time it is released, the next versions of C# and VB.NET will be supporting Generics. So what does this imply for you, the developer? Well, here it goes:
MSIL will have new opcodes to support generics
You will be able to use the C++ template concepts to write code that will work against various data types
You will not need to fall back on System.Object to implement such kind of generic system.
The FCL (Framework Class Library) will have support for various general-purpose classes, such as List, with their Generic versions.
It means that you could write code, such as below, which specifies what data-type will the Stack implementation use during object instantiation:
GenQueue
But how do you write code that uses Generics?
Will Generics work just like C++ templates? Do they give any performance benefits? Let’s answer these questions.
Understanding the How
To exemplify the concept of Generics, we will write an implementation of the Queue data structure. This data structure, thus, will be written once but can be used in the context of various data types, as you shall see. Below is the GenericQueue implementation as a .NET class by the name
GenQueue:
public class GenQueue
{
// private working members
T<> arrData = null;
int iSize; // current working size
int iCurIndex; // current insertion index
int iCurRemovalIndex; // current removal index;
// constructors
public GenQueue()
{
// create a queue of the default size
iSize = 10;
arrData = new T
iCurIndex = 0;
iCurRemovalIndex = 0;
}
public GenQueue(int iCustomSize)
{
// create a queue of the user specified size
iSize = iCustomSize;
arrData = new T
iCurIndex = 0;
iCurRemovalIndex = 0;
}
// Add: Inserts an item in the queue
public bool Insert(T tData)
{
if (iCurIndex==iSize)
return false; // the queue is full
// insert item at the queue end...
arrData
return true;
}
// Remove: Removes an item from the front of the queue
public T Remove()
{
// are there any items in the queue?
if (iCurIndex==iCurRemovalIndex)
throw new Exception(“Queue is empty!”);
T tData = arrData
iCurRemovalIndex++; // move to the next removal point
return tData;}}
The first noticeable difference can be seen in the class declaration itself:
public class GenQueue
GenQueue
As you can see, this instantiation is different from the conventional way of instantiating the class. The angle brackets are used to specify the data type to be used, which is int in the above statement. This implies that for this particular instantiation, the T in
public class GenQueue
shall be an alias for int. Now that any usage of T shall imply the usage of int, re-read the entire class implementation code and replace all occurrences of T with int. Thus,
T<> arrData = null;
is actually read as
int<> arrData = null;
And this is how the .NET JITter sees the code. Subsequent usage to add and/or remove elements to/from the generic queue is rather simple. Here’s how a queue of double elements shall be created:
GenQueue
refGQDouble.Insert(1.5);
refGQDouble.Insert(2.6);
refGQDouble.Insert(3.7);
Console.WriteLine(“{0}”, refGQDouble.Remove());
Console.WriteLine(“{0}”, refGQDouble.Remove());
Console.WriteLine(“{0}”, refGQDouble.Remove());
As you can understand for yourself, the code simply creates a generic queue to contain elements of double data-type, adds three elements and then removes them from the queue, while displaying them alongside.
The source code accompanying this article has the complete code that also contains the consumer of the above shown
Gen Queue class. Do refer to it. Of course, it can only be compiled with .NET
Framework Whidbey.
Kumar Gaurav Khanna
runs wintoolzone.com