Introducing .NET Generics

By Robert Chartier

When we look at the term "generic", unrelated to the programming world, it simply means something that is not tied to any sort of brand name. For example, if we purchase some generic dish soap, soap that has no brand name on it, we know that we are buying dish soap and expect it to help us clean our dishes, but we really don't know what exact brand (if any) will be inside the bottle itself. We can treat it as dish soap even though we don't really have any idea of its exact contents.

Think of Generics in this manner. We can refer to a class, where we don't force it to be related to any specific Type, but we can still perform work with it in a Type-Safe manner. A perfect example of where we would need Generics is in dealing with collections of items (integers, strings, Orders etc.). We can create a generic collection than can handle any Type in a generic and Type-Safe manner. For example, we can have a single array class that we can use to store a list of Users or even a list of Products, and when we actually use it, we will be able to access the items in the collection directly as a list of Users or Products, and not as objects (with boxing/unboxing, casting).

"Generic" Collections as we see them today

Currently, if we want to handle our Types in a generic manner, we always need to cast them to a System.Object, and we lose any benefit of a rich-typed development experience. For example, I'm sure most of us are familiar with the System.Collection.ArrayList class in Framework v1 and v1.1. If you have used it at all, you will notice a few things about it:

1. It requires that you store everything in it as an object


public virtual int Add(object value);
public virtual object this[int index] {get; set;}


2. You need to cast up in order to get your object back to its actual Type

3. Performance is really lacking, especially when iterating with foreach()

4. It performs no type safety for you (no exceptions are thrown even if you add objects of different types to a single list)


System.Collections.ArrayList list = new System.Collections.ArrayList();

list.Add("a string");
list.Add(45); //no exception thrown
list.Add(new System.Collections.ArrayList()); //no exception

foreach(string s in list) { //exception will be thrown!
  System.Console.WriteLine(s);
}

For some situations we may feel the need to implement IEnumerable and IEnumerator in order to create a custom collection of our given Type, that is, a Type-safe collection for our needs. If you had a User object, you could create another class (which implements IEnumerable and IEnumerator, or just IList) that allows you to only add and access User objects, even though most implementations will still store them as objects. It is a lot of work implementing these two interfaces, and you can imagine the work needed to create this additional collection class every time you wanted a Type-safe collection.

The third and final way of creating a collection of items is by simply creating an array of that type, for example:



string[] mystrings = new string[]{"a", "b", "c"};

This will guarantee Type safety, but is not very reusable nor very friendly to work with. Adding a new item to this collection would mean needing to create a temporary array and copy the elements into this new temporary array, resizing the old array, copying the data back into it, and then adding the new item to the end of that collection. In my humble opinion, this is too much work that tends to be very error prone.

What we need is a way to create a Type-safe collection of items that we can use for any type imaginable. This template, or generic class, should be able to perform all of the existing duties that we need for our collections: adding, removing, inserting, etc. The ideal situation is for us to be able to create this generic collection functionality once and never have to do it again. You must also consider other types of collections that we commonly work with and their functionality, such as a Stack (First in, Last out) or a Queue (First In, First out), etc. It would be nice to be able to create different types of generic collections that behave in standard ways.

In the next I will show you how to create your first Generic Type.

Creating Our First Generic Type

In this section we will create a very simple generic class and demonstrate how it can be used as a container for a variety of other Types. Below is a simple example of what a generic class could look like:



public class Col<T> {
  T t;
  public T Val{get{return t;}set{t=value;}}
}

There are a few things to notice. The class name "Col<T>" is our first indication that this Type is generic, specifically the brackets containing the Type placeholder. This Type placeholder "T" is used to show that if we need to refer to the actual Type that is going to be used when we write this class, we will represent it as "T". Notice on the next line the variable declaration "T t;" creates a member variable with the type of T, or the generic Type which we will specify later during construction of the class (it will actually get inserted by the Common Language Runtime (CLR) automatically for us). The final item in the class is the public property. Again, notice that we are using the Type placeholder "T" to represent that generic type for the type of that property. Also notice that we can freely use the private variable "t" within the class.

In order to use this class to hold any Type, we simply need to create a new instance of our new Type, providing the name of the Type within the "<>" brackets and then use that class in a Type-safe manner. For example:


public class ColMain {
  public static void Main() {
	//create a string version of our generic class
    Col<string> mystring = new Col<string>();
	//set the value
    mystring.Val = "hello";
    
	//output that value
    System.Console.WriteLine(mystring.Val);
	//output the value's type
    System.Console.WriteLine(mystring.Val.GetType());
    
	//create another instance of our generic class, using a different type
    Col<int> myint  = new Col<int>();
	//load the value
    myint.Val = 5;
	//output the value
    System.Console.WriteLine(myint.Val);
	//output the value's type
    System.Console.WriteLine(myint.Val.GetType());
    
  }
}


When we compile the two classes above and then run them, we will see the following output:

hello
System.String
5
System.Int32

Even though we used the same class to actually hold our string and int, it keeps their original type intact. That is, we are not going to and from a System.Object type just to hold them.

Generic Collections

The .NET team has provided us with a number of generic collections to work with in the the latest version of the .NET Framework. List, Stack, and Queue are all going to be implemented for us. Let's see an example on how to use the provided Generic List class.

For this example we want to be able to hold a collection of a Type that we create, which we used to represent a User in our system. Here is the definition for that class:


namespace Rob {
  public class User {
    protected string name;
    protected int age;
    public string Name{get{return name;}set{name=value;}}
    public int Age{get{return age;}set{age=value;}}
  }
}

Now that we have our User defined, let's create an instance of the .NET Framework Generic version of a simple List:

System.Collections.Generic.List<Rob.User> users 
= new System.Collections.Generic.List<Rob.User>();


Notice the new "Generic" namespace within the System.Collections namespace. This is where we will find all the new classes for our use. The "List" class within that namespace is synonymous with the typical System.Collections.ArrayList class, which I'm sure most of us are very familiar with by now. Please note that although they are similar there are several important differences.

So now that we have a Type-safe list of our User class, let's see how we can use this class. What we will do is simply loop 5 times and create a new User and add that User to our users collection above:


    for(int x=0;x<5;x++) {
      Rob.User user = new Rob.User();
      user.Name="Rob" + x;
      user.Age=x;
      users.Add(user);
    } 

This should seem straight forward to you by now. In the next step we will iterate over that same collection and output each item to the console:

foreach(Rob.User user in users) {
     System.Console.WriteLine(
System.String.Format("{0}:{1}", user.Name, user.Age)
);
}

This is slightly different that what we are used to. What you should notice right off the bat is that we do not have to worry about the Type being "Rob.User". This is because our generic collection is working in a Type-safe manner; it will always be what we expect.

Another way to output the same list would be to use a simple for() loop instead, and in this case we do not have to cast the object out of the collection in order to use it properly:


for(int x=0;x<users.Count;x++) {
System.Console.WriteLine(
System.String.Format("{0}:{1}", users[x].Name, users[x].Age)
);
}

No more silly casting or boxing involved. Here is the complete listing of the source plus the output of the result of executing the console application:

User.cs


namespace Rob {
  public class User {
    protected string name;
    protected int age;
    public string Name{get{return name;}set{name=value;}}
    public int Age{get{return age;}set{age=value;}}
  }
}


Main.cs

public class M {
  public static void Main(string[] args) {
    System.Collections.Generic.List<Rob.User> users = new System.Collections.Generic.List<Rob.User>();
    for(int x=0;x<5;x++) {
      Rob.User user = new Rob.User();
      user.Name="Rob" + x;
      user.Age=x;
      users.Add(user);
    }

    foreach(Rob.User user in users) {
      System.Console.WriteLine(System.String.Format("{0}:{1}", user.Name, user.Age));
    }
    System.Console.WriteLine("press enter");
    System.Console.ReadLine();

    for(int x=0;x<users.Count;x++) {
      System.Console.WriteLine(System.String.Format("{0}:{1}", users[x].Name, users[x].Age));
    }
    
  }
}

Output

Rob0:0
Rob1:1
Rob2:2
Rob3:3
Rob4:4
press enter

Rob0:0
Rob1:1
Rob2:2
Rob3:3
Rob4:4

More on Generics

More Generics features in the latest release of the .NET Framework include Generic Methods and Constraints. A generic method is very straight forward. Consider this example:


public static T[] CreateArray<T>(int size) {
	return new T[size];
}


This static method simply creates a method of the given Type "T" and of the given "size" and returns it to the caller. An example of calling this method would be:

string[] myString = CreateArray<string>(5);

This will new up an instance of our string array, with an initial size of 5. You should take time to investigate the new version of the framework. You will be surprised at all the little helpful features like this.

Lastly, we should take a quick look at constraints. A constraint is setup to limit the Types which the Generic can accept. Let's say for example we had a generic type:


public class Dictionary<K, V> where K : IComparable {}


Notice the "where" clause on this class definition. It is forcing the K Type to be of Type IComparable. If K does NOT implement IComparable, you will get a Compiler error. Another type of constraint is a constructor constraint:

public class Something<V> where V: new() {}

In this example V must have at least the default constructor available, if not the Compiler will throw an error.

Conclusion

This article has introduced you to the new and exciting world of Generics. I hope you learned something with this article, and are beginning to prepare yourself for the latest release of the .NET Framework.

References

System.Collections.ArrayList Class:
http://msdn.microsoft.com/library/en-us/cpref/html/frlrfSystemCollectionsArrayListClassTopic.asp

System.Object:
http://msdn.microsoft.com/library/en-us/cpref/html/frlrfSystemObjectClassTopic.asp

Guidelines for Casting Types
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpgenref/html/cpconcasts.asp

About the Author

Robert Chartier has developed IT solutions for more than nine years with a diverse background in both software and hardware development. He is internationally recognized as an innovative thinker and leading IT architect with frequent speaking engagements showcasing his expertise. He's been an integral part of many open forums on cutting-edge technology, including the .NET Framework and Web Services. His current position as vice president of technology for Santra Technology (http://www.santra.com) has allowed him to focus on innovation within the Web Services market space.

He uses expertise with many Microsoft technologies, including .NET, and a strong background in Oracle, BEA Systems, Inc.'s BEA WebLogic, IBM, Java 2 Platform Enterprise Edition (J2EE), and similar technologies to support his award-winning writing. He frequently publishes to many of the leading developer and industry support Web sites and publications. He has a bachelor's degree in Computer Information Systems..



Comments

  • Researcher Discovers High-risk nike fixation

    Posted by BobHotgloff on 05/03/2013 05:02am

    Concise report demonstrates to you the workings of the nike combined with the things that one should do right away. [url=http://www.mizunogoruhujp.com/]ミズノ グローブ[/url] The Secret For mizuno [url=http://www.mizunogoruhujp.com/ミズノ-ゴルフクラブ-c-1.html]ミズノ アイアン[/url] Extra short summary aids you with most of the cogs and wheels linked with nike and consequently everything that you must do right away. [url=http://www.mizunogoruhujp.com/ゴルフグローブ-c-33.html]ミズノ グローブ[/url] The things everybody else is doing for the nike and furthermore the thing you will want to perform completely different. [url=http://www.mizunogoruhujp.com/ゴルフバッグ-c-7.html]ミズノ[/url] Third party essay unwraps Four completely new things on mizuno that nobody is bringing up. [url=http://www.mizunogoruhu.com/]ミズノ アイアン[/url] One specific double twirl on nike [url=http://www.mizunogoruhu.com/ミズノmizuno-クラブ-c-4.html]ミズノ グラブ[/url] Devices and manufacturing throughout Brooklyn - nike has left with no thanks [url=http://www.mizunogoruhu.com/ミズノmizuno-アイアン-c-3.html]ミズノ アイアン[/url] Effectual methods for nike that you can use starting off this afternoon. [url=http://www.mizunogoruhu.com/ミズノmizuno-バッグ-c-5.html]ミズノ[/url] Short publishing clearly shows the indeniable details about mizuno and the way it might may affect you.

    Reply
  • Nice one there

    Posted by Slalaleasyday on 03/13/2013 07:26am

    Nice Post. ---------- I love http://youtube.com

    Reply
  • Zahid

    Posted by Zahid on 01/20/2013 11:38pm

    very very helpful.....Thanx

    Reply
  • stack correction

    Posted by ranjith on 12/27/2012 07:37am

    Thank you for the post. I was helpful. However, I would like you to correct that Stack is LIFO (last in first out), I am sure its just a typo but wanted to bring this to your notice.

    Reply
  • stack correction

    Posted by ranjith on 12/27/2012 07:36am

    Thank you for the post. I was helpful. However, I would like you to correct that Stack is LIFO (last in first out), I am sure its just a typo but wanted to bring this to your notice.

    Reply
Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • On-demand Event Event Date: September 10, 2014 Modern mobile applications connect systems-of-engagement (mobile apps) with systems-of-record (traditional IT) to deliver new and innovative business value. But the lifecycle for development of mobile apps is also new and different. Emerging trends in mobile development call for faster delivery of incremental features, coupled with feedback from the users of the app "in the wild." This loop of continuous delivery and continuous feedback is how the best mobile …

  • QA teams don't have time to test everything yet they can't afford to ship buggy code. Learn how Coverity can help organizations shrink their testing cycles and reduce regression risk by focusing their manual and automated testing based on the impact of change.

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds