This is a follow up from my presentation to the .NET Wizards user group for people who may not have been able to make it out. If you read this and have any questions, feel free to email me or leave a comment in the comment section and I will get back to you.
Generics can be confusing, but not if you picture them the right way and know the purpose of their existence.
Back in the days of .NET 1.1 if you wanted an object oriented framework sooner or later you would need a collection. A collection’s purpose is usually to hold a bunch of associated objects. So you would get a collection filled with intergers, strings or business objects. An example of a collection that can hold Employee objects looks like this:
1 using System;
2 using System.Collections;
3
4 namespace GenericsDemoCS
5 {
6 public class EmployeeCollection : CollectionBase
7 {
8 public Employee this[int index]
9 {
10 get
11 {
12 return (Employee)List[index];
13 }
14 set
15 {
16 List[index] = value;
17 }
18 }
19
20 public int Add(Employee value)
21 {
22 return (List.Add(value));
23 }
24
25 public int IndexOf(Employee value)
26 {
27 return (List.IndexOf(value));
28 }
29
30 public void Insert(int index, Employee value)
31 {
32 List.Insert(index, value);
33 }
34
35 public void Remove (Employee value)
36 {
37 List.Remove(value);
38 }
39
40 public bool Contains(Employee value)
41 {
42 return (List.Contains(value));
43 }
44 }
45 }
As you can see, all of the methods in the collection take in a Employee object. It is really just a list of Employee objects. There is one main problem with this approach:
Only Employee objects can use this list. For each new objet you have to create a new list.
To solve this problem in the .NET 1.1 Framework you could create a list that is of the deault type of object like this:
1 using System;
2 using System.Collections;
3
4 namespace GenericsDemoCS
5 {
6 public class ObjectCollection : CollectionBase
7 {
8 public Object this[int index]
9 {
10 get
11 {
12 return List[index];
13 }
14 set
15 {
16 List[index] = value;
17 }
18 }
19
20 public int Add(Object value)
21 {
22 return (List.Add(value));
23 }
24
25 public int IndexOf(Object value)
26 {
27 return (List.IndexOf(value));
28 }
29
30 public void Insert(int index, Object value)
31 {
32 List.Insert(index, value);
33 }
34
35 public void Remove(Object value)
36 {
37 List.Remove(value);
38 }
39
40 public bool Contains(Object value)
41 {
42 return (List.Contains(value));
43 }
44 }
45 }
This collection can hold a lot of different types, however anyone can put anything in it. It is essentially this:

Thats right, it is a bucket. It can hold anything you or anyone else wants to put in it. You may think it is holding all of your integer objects when really it is holding this:

So if you want type safe collections, you have to create tons of collections that can only hold specific types and you end up with this by the end of it all:

Keep in mind that one of those buckets can only hold integers, one can only hold strings and one can only hold Employee objects. What I am trying to get at here is that you have a lot of similar code that isn’t very reusable.
Generics to the Rescue
Along comes the .NET 2.0 Framework and Generics. Generics solve the above problems very elegantly. Generics solve “the bucket problem” with a structure like this:

It is the same collection as before but this time you have type safety. Think of each shape on the childs toy as a specific type like an integer, a string or an Employee object. If at the time you specify your list you say you want your list to hold integers it can only hold integers, so only the integer hole in the childs toy would remain.
Here is the same list as the object list above except this time it takes advantage of Generics:
1 using System;
2 using System.Collections;
3 using System.Text;
4
5 namespace GenericsDemoCS
6 {
7 class GenericCollection : System.Collections.CollectionBase
8 {
9
10 public ItemType this[int index]
11 {
12 get
13 {
14 return (ItemType)List[index];
15 }
16 set
17 {
18 List[index] = value;
19 }
20 }
21
22 public int Add(ItemType value)
23 {
24 return (List.Add(value));
25 }
26
27 public int IndexOf(ItemType value)
28 {
29 return (List.IndexOf(value));
30 }
31
32 public void Insert(int index, ItemType value)
33 {
34 List.Insert(index, value);
35 }
36
37 public void Remove(ItemType value)
38 {
39 List.Remove(value);
40 }
41
42 public bool Contains(ItemType value)
43 {
44 return (List.Contains(value));
45 }
46 }
47 }
Notice the “ItemType” this is a placeholder and can be anything you want to call it. The difference between this class and the other collection classes is that when you declare the list like in the code below, the list can only hold that type that you have specified (the list below can only hold strings).
GenericCollection<string> genericList = new GenericCollection<string>();
genericList.Add("steve");