A Basic Generic Collection
In Listing 1, I have a really simple base class called Person. (Notice that all the code in this article uses a C# namespace called UsingGenerics.)
Listing 1 A simple base class.
namespace UsingGenerics { public class Person { private String name; public Person() { } public string Name { get { return name; } protected set { name = value; } } } }
The Person class has a private data member called name. Also, I have a property accessor and a protected mutator (see the set clause in Listing 1). To make things a little more interesting, I'm going to create two subclasses from Person—one called Employee and the other called Contractor. These two subclasses are shown in Listing 2.
>Listing 2 Two subclasses derived from Person.
namespace UsingGenerics { public class Employee : Person { public Employee(String name) : base(name) { } } public class Contractor : Person { public Contractor(String name) : base(name) { } }
The two subclasses of Person in Listing 2 make calls into the base class constructor. The reason I define two subclasses is so that I can do different things with each subclass. An example is vacation allocation. A contractor is typically not allocated paid annual leave, whereas an employee receives that benefit. These semantics can easily be incorporated into the Listing 2 subclasses by using new methods and data members. This approach is classic object-oriented design.
However, I'm going to use the class hierarchy from Listings 1 and 2 to illustrate generic collection behavior. Let's get straight into this with the code in Listing 3, which illustrates such a generic collection class.
Listing 3 A generic collection class.
public class GenericCollection<T> : IEnumerable<T> { private List<T> genericCollection = new List<T>(); public GenericCollection() { } public List<T> MyGenericCollection { get { return genericCollection; } } IEnumerator<T> IEnumerable<T>.GetEnumerator() { return genericCollection.GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return genericCollection.GetEnumerator(); } }
Listing 3 looks awfully complex, but it really isn't! Notice the funny little angle brackets (<>) surrounding the letter T—this is our required generic element. Remember that I said that a generic type is only created at runtime. At compile time, what we have in Listing 3 is something like a blueprint for a class. The actual class is created only at runtime. Soon you'll see why this distinction is important. For now, let's make this example more concrete by putting the generic collection class from Listing 3 to work (see Listing 4).
Listing 4 Using a generic collection class.
public static void Main(string[] args) { Contractor contractor = new Contractor("A Contractor"); Employee employee = new Employee("An Employee"); GenericCollection<Person> genericCollection = new GenericCollection<Person>(); genericCollection.MyGenericCollection.Add(employee); genericCollection.MyGenericCollection.Add(contractor); foreach (Person p in genericCollection) { Console.WriteLine("Person called: " + p.Name); } Console.ReadLine(); }
In Listing 4, I instantiate an object of the Contractor class and an object of the Employee class. In each case, I pass in a name that is itself passed to the base class constructor. Next, I instantiate an object of the GenericCollection class.
However, notice that in the instantiation of the object of GenericCollection, I no longer use the T type from Listing 3. Instead, I've bolted in a concrete type—in this case, the Person class. From here on, my object called genericCollection refers to a collection of instances of the Person class. Once you understand this point, you're a long way toward understanding generics.
After I create the collection class, I add my two objects to it; namely, contractor and employee. I then iterate through the collection to see what objects are contained in the collection. Let's see what this code looks like when it's executed, as illustrated in Listing 5.
Listing 5 Executing the code.
Person called: An Employee Person called: A Contractor
Nothing too exciting in Listing 5—I've added two objects to the collection and I then list their names. But this gives rise to a question....