Excerpt of Pro C# 2008 and the .NET 3.5 Platform

Nov 26, 08:20 pm

The System.Collections.Generic Namespace

Generic types are found sprinkled throughout the .NET base class libraries; however, the System.Collections.Generic namespace is chock-full of them (as its name implies). Like its nongeneric counterpart (System.Collections), the System.Collections.Generic namespace contains numerous class and interface types that allow you to contain subitems in a variety of containers. Not surprisingly, the generic interfaces mimic the corresponding nongeneric types in the System.Collections namespace:

  • ICollection<T>
  • IComparer<T>
  • IDictionary<TKey, TValue>
  • IEnumerable<T>
  • IEnumerator<T>
  • IList<T>

Note: By convention, generic types specify their placeholders using common names. Although any letter (or word) will do, typically T is used to represent types, TKey is used for keys, and TValue is used for values.

The System.Collections.Generic namespace also defines a number of classes that implement many of these key interfaces. Table 10-5 describes the core class types of this namespace, the interfaces they implement, and any corresponding type in the System.Collections namespace.

Table 10-5. Classes of System.Collections.Generic

Generic Class in Nongeneric CounterpartSystem.CollectionsMeaning in Life
Collection<T>CollectionBaseThe basis for a generic collection
Comparer<T>ComparerCompares two generic objects for equality
Dictionary<TKey, TValue>HashtableA generic collection of name/value pairs
List<T>ArrayListA dynamically resizable list of items
Queue<T>QueueA generic implementation of a first-in, first-out (FIFO) list
SortedDictionary<TKey, TValue>SortedListA generic implementation of a sorted set of name/value pairs
Stack<T>StackA generic implementation of a last-in, first-out (LIFO) list
LinkedList<T>N/AA generic implementation of a doubly linked list
ReadOnlyCollection<T>ReadOnlyCollectionBaseA generic implementation of a set of read-only items

The System.Collections.Generic namespace also defines a number of auxiliary classes and structures that work in conjunction with a specific container. For example, the LinkedListNode<T> type represents a node within a generic LinkedList<T>, the KeyNotFoundException exception is raised when attempting to grab an item from a container using a nonexistent key, and so forth.
As you can see from Table 10-5, many of the generic collection classes have a nongeneric counterpart in the System.Collections namespace (some of which are identically named). Because the generic classes mimic their nongeneric types so closely, I will not provide a detailed examination of each generic item (once you understand how to work with a given container, the remaining items are quite straightforward). Instead, I’ll make use of List<T> to illustrate the process of working with generics. If you require details regarding other members of the System.Collections.Generic namespace, consult the .NET Framework 3.5 documentation.

Examining the List<T> Type

Like nongeneric classes, generic classes are created with the new keyword and 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<T> 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 myInts = new List();

// Create a List containing SportsCar objects. List myCars = new List(); // Create a List containing Person objects. List myPeople = new List(); }

At this point, you might wonder what exactly becomes of the specified placeholder value. If you were to make use of the Visual Studio 2008 Code Definition window (see Chapter 2), you will find that the placeholder T is used throughout the definition of the List<T> type. Here is a partial listing (note the items in bold):


// 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 were really defined as follows:


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 follows:


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.


This excerpt was from Pro C# 2008 and the .NET 3.5 Platform, Fourth Edition by Andrew Troelsen.

Founders at Work


    1. I am beginer in c# but worked with php,Very good details on this page regarding my question.




Add your comments

Please keep your comments relevant to this blog entry: inappropriate or purely promotional comments may be removed. To add hyperlink, please follow this example: "your link text":http://your.link.url