Understanding Generics—Type Safety and Strongly Typed Collections
Microsoft .NET Framework, ASP.NET, Visual C# (CSharp, C Sharp, C-Sharp) Developer Training, Visual Studio
Type Safety and Strongly Typed Collections
In the world of .NET prior to version 2.0, programmers attempted to address type safety by building custom strongly typed collections. To illustrate, assume you wish to create a custom collection that can only contain objects of type Person:
public class Person { // Made public for simplicity. public int currAge; public string fName, lName; public Person(){} public Person(string firstName, string lastName, int age) { currAge = age; fName = firstName; lName = lastName; } public override string ToString() { return string.Format("{0}, {1} is {2} years old", lName, fName, currAge); } }
To build a person collection, you could define a System.Collections.ArrayList member variable
within a class named PeopleCollection and configure all members to operate on strongly typed
Person objects, rather than on generic System.Objects:
public class PeopleCollection : IEnumerable { private ArrayList arPeople = new ArrayList(); public PeopleCollection(){} // Cast for caller. public Person GetPerson(int pos) { return (Person)arPeople[pos]; } // Only insert Person types. public void AddPerson(Person p) { arPeople.Add(p); } public void ClearPeople() { arPeople.Clear(); } public int Count { get { return arPeople.Count; } } // Foreach enumeration support. IEnumerator IEnumerable.GetEnumerator() { return arPeople.GetEnumerator(); } }
With these types defined, you are now assured of type safety, given that the C# compiler will be able to determine any attempt to insert an incompatible type:
static void Main(string[] args) { Console.WriteLine("***** Custom Person Collection *****\n"); PeopleCollection myPeople = new PeopleCollection(); myPeople.AddPerson(new Person("Homer", "Simpson", 40)); myPeople.AddPerson(new Person("Marge", "Simpson", 38)); myPeople.AddPerson(new Person("Lisa", "Simpson", 9)); myPeople.AddPerson(new Person("Bart", "Simpson", 7)); myPeople.AddPerson(new Person("Maggie", "Simpson", 2)); // This would be a compile-time error! myPeople.AddPerson(new Car()); foreach (Person p in myPeople) Console.WriteLine(p); Console.ReadLine(); }
While custom collections do ensure type safety, this approach leaves you in a position where
you must create a (almost identical) custom collection for each type you wish to contain. Thus, if
you need a custom collection that will be able to operate only on classes deriving form the Car base
class, you need to build a very similar type:
public class CarCollection : IEnumerable { private ArrayList arCars = new ArrayList(); public CarCollection(){} // Cast for caller. public Car GetCar(int pos) { return (Car) arCars[pos]; } // Only insert Car types. public void AddCar(Car c) { arCars.Add(c); } public void ClearCars() { arCars.Clear(); } public int Count { get { return arCars.Count; } } // Foreach enumeration support. IEnumerator IEnumerable.GetEnumerator() { return arCars.GetEnumerator(); } }
As you may know from firsthand experience, the process of creating multiple strongly typed
collections to account for various types is not only labor intensive, but also a nightmare to maintain.
Generic collections allow us to delay the specification of the contained type until the time of creation.
Don’t fret about the syntactic details just yet, however. Consider the following code, which makes
use of a generic class named System.Collections.Generic.List<> to create two type-safe container
objects:
static void Main(string[] args) { // Use the generic List type to hold only people. List<Person> morePeople = new List<Person>(); morePeople.Add(new Person()); // Use the generic List type to hold only cars. List<Car> moreCars = new List<Car>(); // Compile-time error! moreCars.Add(new Person()); }
|

