- Introduction
- Using Generic Collections
- Implementing a Generic Class
- Adding Type Constraints
- Summary
Implementing a Generic Class
A reasonable way to implement something new is to build on something old. We already know something about strongly typed collections, and a good technique for building generic classes is to take a specific class and then remove the data types. That said, let's define a strongly typed collection, CustomerList, and see what it takes to convert it to a generic class.
Listing 2 defines a class CustomerList. The subsections that follow convert CustomerList to List<T>.
Listing 2 Defining the class CustomerList.
using System; using System.Collections; using System.Text; namespace Generics { public class CustomerList : CollectionBase { public CustomerList() { } public Customer this[int index] { get { return (Customer)List[index]; } set { List[index] = value; } } public int Add(Customer value) { return List.Add(value); } } }
Defining the Class Header
If we're defining a generic class, we need to convert the class header to a generic class header. All we need to do is name the parameters and change the class name to something generic. List<T> has just one parameter, T, and because we're working backward we know the class name, List. Listing 3 shows the header for the new class in Listing 2.
Listing 3 A generic class header showing the parameterized argument, T.
using System; using System.Collections; using System.Text; namespace Generics { public class List<T> : CollectionBase {
Implementing Generic Fields
If we needed to convert any fields to generic fields, we would simply change their types to T (or whatever parameter that field represents). The generic List doesn't need any fields, but suppose there existed a private integer field named foo that we'd like to make generic. We would redefine it as follows:
private T foo;
When the parameter T is filled in for the class, List T would also be filled in for foo.
Defining Generic Methods
What remains is to define all other features in terms of the parameterized type as needed. This includes properties, methods, and events. For our example, everywhere Customer appears, we replace it with the parameter T. The completed generic List class is shown in Listing 4.
Listing 4 A lightweight parameterized generic List class based on System.Collections.CollectionBase.
using System; using System.Collections; using System.Text; namespace Generics { public class List<T> : CollectionBase { public List(){ } public T this[int index] { get { return (T)List[index]; } set { List[index] = value; } } public int Add(T value) { return List.Add(value); } } }
To test the custom list, comment out the using statement for the System.Collections.Generic namespace and use List<T> from Listing 4 in the code for Listing 1; it will work the same way.
It's worth noting that .NET's List<T> is fully evolved and contains many more features than our sample, but Listing 4 shows how easy the mechanics are for defining custom generic classes.