Understanding Generics—Examining the List(T) Type
Microsoft .NET Framework, ASP.NET, Visual C# (CSharp, C Sharp, C-Sharp) Developer Training, Visual Studio
Examining the List<T> Type
Like nongeneric classes, generic classes are heap-allocated objects, and therefore must be new-ed with
any required constructor arguments. In addition, you are required to specify the type(s) to be substituted
for the type parameter(s) defined by the generic type. For example, System.Collections.Generic.List<T>
requires you to specify a single value that describes the type of item the List<T> will operate upon.
Therefore, if you wish to create three List<> objects to contain integers and SportsCar and Person
objects, you would write the following:
static void Main(string[] args) { // Create a List containing integers. List<int> myInts = new List<int>(); // Create a List containing SportsCar objects. List<SportsCar> myCars = new List<SportsCar>(); // Create a List containing Person objects. List<Person> myPeople = new List<Person>(); }
At this point, you might wonder what exactly becomes of the specified placeholder value. If you
were to make use of the Visual Studio 2005 Code Definition View window, you will find that the placeholder T is used throughout the definition of the List<T> type. Here is a partial
listing:
// A partial listing of the List<T> type. namespace System.Collections.Generic { public class List<T> : IList<T>, ICollection<T>, IEnumerable<T>, IList, ICollection, IEnumerable { ... public void Add(T item); public IList<T> AsReadOnly(); public int BinarySearch(T item); public bool Contains(T item); public void CopyTo(T[] array); public int FindIndex(System.Predicate<T> match); public T FindLast(System.Predicate<T> match); public bool Remove(T item); public int RemoveAll(System.Predicate<T> match); public T[] ToArray(); public bool TrueForAll(System.Predicate<T> match); public T this[int index] { get; set; } .. } }
When you create a List<T> specifying SportsCar types, it is as if the List<T> type was really
defined as so:
namespace System.Collections.Generic { public class List<SportsCar> : IList<SportsCar>, ICollection<SportsCar>, IEnumerable<SportsCar>, IList, ICollection, IEnumerable { ... public void Add(SportsCar item); public IList<SportsCar> AsReadOnly(); public int BinarySearch(SportsCar item); public bool Contains(SportsCar item); public void CopyTo(SportsCar[] array); public int FindIndex(System.Predicate<SportsCar> match); public SportsCar FindLast(System.Predicate<SportsCar> match); public bool Remove(SportsCar item); public int RemoveAll(System.Predicate<SportsCar> match); public SportsCar [] ToArray(); public bool TrueForAll(System.Predicate<SportsCar> match); public SportsCar this[int index] { get; set; } .. } }
Of course, when you create a generic List<T>, the compiler does not literally create a brand-new
implementation of the List<T> type. Rather, it will address only the members of the generic type
you actually invoke. To solidify this point, assume you exercise a List<T> of SportsCar objects as so:
static void Main(string[] args) { // Exercise a List containing SportsCars List<SportsCar> myCars = new List<SportsCar>(); myCars.Add(new SportsCar()); Console.WriteLine("Your List contains {0} item(s).", myCars.Count); }
If you examine the generated CIL code using ildasm.exe, you will find the following substitutions:
.method private hidebysig static void Main(string[] args) cil managed { .entrypoint .maxstack 2 .locals init ([0] class [mscorlib]System.Collections.Generic.'List`1' <class SportsCar> myCars) newobj instance void class [mscorlib]System.Collections.Generic.'List`1' <class SportsCar>::.ctor() stloc.0 ldloc.0 newobj instance void CollectionGenerics.SportsCar::.ctor() callvirt instance void class [mscorlib]System.Collections.Generic.'List`1' <class SportsCar>::Add(!0) nop ldstr "Your List contains {0} item(s)." ldloc.0 callvirt instance int32 class [mscorlib]System.Collections.Generic.'List`1' <class SportsCar>::get_Count() box [mscorlib]System.Int32 call void [mscorlib]System.Console::WriteLine(string, object) nop ret }
Now that you’ve looked at the process of working with generic types provided by the base class libraries, in the remainder of this chapter you’ll examine how to create your own generic methods, types, and collections.
|

