Section 14.4. Framework Generic Collections


14.4. Framework Generic Collections

The .NET Framework provides four very useful generic collections , as enumerated earlier ( List , Stack , Queue , and Dictionary ). The most common case is that rather than writing your own collection, you'll use one of the collection classes provided for you. Each is described in turn in the next few sections.

14.4.1. Generic Lists: List<T>

The classic problem with the Array type is its fixed size . If you do not know in advance how many objects an array will hold, you run the risk of declaring either too small an array (and running out of room) or too large an array (and wasting memory).

The generic List class (which replaces the old non-generic ArrayList ) is, essentially , an array whose size is dynamically increased as required. Lists provide a number of useful methods and properties for their manipulation.. Some of the most important are shown in Table 14-2.

Table 14-2. List properties and methods

Method or property

Purpose

Capacity

Property to get or set the number of elements the List can contain. This value is increased automatically if count exceeds capacity. You might set this value to reduce the number of reallocations, and you may call trim( ) to reduce this value to the actual Count .

Count

Property to get the number of elements currently in the list.

Item( )

Gets or sets the element at the specified index. This is the indexer for the List class. [a]

Add( )

Public method to add an object to the List .

AddRange( )

Public method that adds the elements of an ICollection to the end of the List .

BinarySearch( )

Overloaded public method that uses a binary search to locate a specific element in a sorted List .

Clear( )

Removes all elements from the List .

Contains( )

Determines if an element is in the List .

CopyTo( )

Overloaded public method that copies a List to a one-dimensional array.

Exists( )

Determines if an element is in the List .

Find( )

Returns the first occurrence of the element in the List .

FindAll( )

Returns all the specified elements in the List .

GetEnumerator( )

Overloaded public method that returns an enumerator to iterate through a List .

GeTRange( )

Copies a range of elements to a new List .

IndexOf( )

Overloaded public method that returns the index of the first occurrence of a value.

Insert( )

Inserts an element into List .

InsertRange( )

Inserts the elements of a collection into the List .

LastIndexOf( )

Overloaded public method that returns the index of the last occurrence of a value in the List .

Remove( )

Removes the first occurrence of a specific object.

RemoveAt( )

Removes the element at the specified index.

RemoveRange( )

Removes a range of elements.

Reverse( )

Reverses the order of elements in the List .

Sort ( )

Sorts the List .

ToArray( )

Copies the elements of the List to a new array.

trimToSize( )

Sets the capacity to the actual number of elements in the List .


[a] The idiom in the Framework Class Library is to provide an Item element for collection classes, which is implemented as an indexer in C#.

When you create a List , you do not define how many objects it will contain. You add to the List using the Add( ) method, and the List takes care of its own internal bookkeeping, as illustrated in Example 14-4.

Example 14-4. Working with a List
 using System; using System.Collections.Generic; namespace ListCollection {    // a simple class to store in the List    public class Employee    {       private int empID;       public Employee( int empID )       {          this.empID = empID;       }       public override string ToString(  )       {          return empID.ToString(  );       }       public int EmpID       {          get          {             return empID;          }          set          {             empID = value;          }       }    }    public class Tester    {       static void Main(  )       {          List<Employee> empList = new List<Employee>(  );          List<int> intList = new List<int>(  );          // populate the List          for ( int i = 0; i < 5; i++ )          {             empList.Add( new Employee( i + 100 ) );             intList.Add( i * 5 );          }          // print all the contents          for ( int i = 0; i < intList.Count; i++ )          {             Console.Write( "{0} ", intList[i].ToString(  ) );          }          Console.WriteLine( "\n" );          // print all the contents of the Employee List          for ( int i = 0; i < empList.Count; i++ )          {             Console.Write( "{0} ", empList[i].ToString(  ) );          }          Console.WriteLine( "\n" );          Console.WriteLine( "empList.Capacity: {0}", empList.Capacity );       }    } } 

The output looks like this:

 0 5 10 15 20     100 101 102 103 104     empArray.Capacity: 8 

The List class has a property, Capacity , which is the number of elements the List is capable of storing; however, this capacity is automatically doubled each time you reach the limit.

14.4.1.1. Creating objects that can be sorted by the generic list

The List implements the Sort( ) method. You can sort any List that contains objects that implement IComparable . All the built-in types do implement this interface, so you can sort a List<integer> or a List<string> .

On the other hand, if you want to sort a List<Employee> , you must change the Employee class to implement IComparable :

 public class Employee : IComparable<Employee> 

As part of the IComparable interface contract, the Employee object must provide a CompareTo( ) method:

 public int CompareTo(Employee rhs)     {        return this.empID.CompareTo(rhs.empID);     } 

The CompareTo( ) method takes an Employee as a parameter (we know this, because the interface is now generic and we can assume type safety). The Employee object must compare itself to this second Employee object and return - 1 if it is smaller than the second Employee , 1 if it is greater, and if the two Employee objects are equal to each other.

It is up to the designer of the Employee class to determine what smaller than , greater than , and equal to mean. In this example, you will delegate the comparison to the empId member. The empId member is an int and uses the default CompareTo( ) method for integer types, which will do an integer comparison of the two values.

To see if the sort is working, you'll add integers and Employee instances to their respective lists with random values. To create the random values, you'll instantiate an object of class Random . To cause your Random instance to generate the random values, you'll call its Next( ) method. One version of the Next( ) method allows you to specify the largest random number you want. In this case, you'll pass in the value 10 to generate a random number between and 10 :

 Random r = new Random(  );     r.Next(10); 

Example 14-5 creates an integer array and an Employee array, populates them both with random numbers , and prints their values. It then sorts both arrays and prints the new values.

Example 14-5. Sorting an integer and an Employee array
 using System; using System.Collections.Generic; namespace IComparable {    // a simple class to store in the array    public class  Employee : IComparable<Employee>  {       private int empID;       public  Employee  ( int empID )       {          this.empID = empID;       }       public override string ToString(  )       {          return empID.ToString(  );       }       public bool Equals(  Employee  other )       {          if ( this.empID == other.empID )          {             return true;          }          else          {             return false;          }       }       // Comparer delegates back to Employee       // Employee uses the integer's default       // CompareTo method  public int CompareTo( Employee rhs )       {          return this.empID.CompareTo( rhs.empID );       }  }    public class  Tester  {       static void Main(  )       {  List<Employee> empList = new List<Employee>(  );   List  <  Int32  > intList = new  List  <  Int32  >(  );          // generate random numbers for          // both the integers and the          // employee id's  Random  r = new  Random  (  );          // populate the array          for ( int i = 0; i < 5; i++ )          {             // add a random employee id             empList.Add( new  Employee  ( r.Next( 10 ) + 100 ) );             // add a random integer             intList.Add( r.Next( 10 ) );          }          // display all the contents of the int array          Console.WriteLine("List<int> before sorting:");          for ( int i = 0; i < intList.Count; i++ )          {  Console  .Write( "{0} ", intList[i].ToString(  ) );          }  Console  .WriteLine( "\n" );          // display all the contents of the Employee array          Console.WriteLine("List<Employee> before sorting:");          for ( int i = 0; i < empList.Count; i++ )          {  Console  .Write( "{0} ", empList[i].ToString(  ) );          }  Console  .WriteLine( "\n" );          // sort and display the int array          Console.WriteLine("List<int>after sorting:");          intList.Sort(  );          for ( int i = 0; i < intList.Count; i++ )          {  Console  .Write( "{0} ", intList[i].ToString(  ) );          }  Console  .WriteLine( "\n" );          // sort and display the Employee array          Console.WriteLine("List<Employee>after sorting:");          //Employee.EmployeeComparer c = Employee.GetComparer(  );          //empList.Sort(c);          empList.Sort(  );          // display all the contents of the Employee array          for ( int i = 0; i < empList.Count; i++ )          {  Console  .Write( "{0} ", empList[i].ToString(  ) );          }  Console  .WriteLine( "\n" );       }    } } 

The output looks like this:

 List<int> before sorting:     6 9 8 3 6     List<Employee> before sorting:     108 103 107 102 109     List<int>after sorting:     3 6 6 8 9     List<Employee>after sorting:     102 103 107 108 109 

The output shows that the lists of integers and Employees were generated with random numbers (and thus the numbers may be different each time you run the program). When sorted, the display shows the values have been ordered properly.

Random number generators do not, technically, create true random numbers; they create what computer scientists call pseudo-random numbers. Microsoft notes: "Pseudo-random numbers are chosen with equal probability from a finite set of numbers. The chosen numbers are not completely random because a definite mathematical algorithm is used to select them, but they are sufficiently random for practical purposes." This is certainly sufficient for our example.


14.4.1.2. Controlling how elements in a generic collection are sorted by implementing IComparer<T>

When you call Sort( ) on the List in Example 14-5, the default implementation of I Comparer is called, which uses QuickSort to call the IComparable implementation of CompareTo( ) on each element in the List .

You are free, however, to create your own implementation of IComparer , which you might want to do if you need control over how the sort ordering is defined. In the next example, you will add a second field to Employee : yearsOfSvc . You want to be able to sort the Employee objects in the List either by ID or by years of service, and you want to make that decision at run time.

To accomplish this, you will create a custom implementation of IComparer , which you will pass to the Sort( ) method of List . In this IComparer class, EmployeeComparer will know how to sort Employees .

To simplify the programmer's ability to choose how a given set of Employees are sorted, we'll add a property WhichComparison , of type Employee.EmployeeComparer.ComparisonType (an enumeration):

 public     Employee.EmployeeComparer.ComparisonType  WhichComparison     {        get { return whichComparison; }        set { whichComparison = value; }     } 

ComparisonType is an enumeration with two values, empID or yearsOfSvc (indicating that you want to sort by employee ID or years of service, respectively):

 public enum ComparisonType     {        EmpID,        YearsOfService     }; 

Before invoking Sort( ) , you will create an instance of EmployeeComparer and set its ComparisonType property:

 Employee.EmployeeComparer c = Employee.GetComparer(  );     c.WhichComparison=Employee.EmployeeComparer.ComparisonType.EmpID;     empArray.Sort(c); 

When you invoke Sort( ) , the List will call the Compare( ) method on the Employee-Comparer , which in turn will delegate the comparison to the Employee.CompareTo( ) method, passing in its WhichComparison property:

 public int Compare(  Employee  lhs,  Employee  rhs )     {         return lhs.CompareTo( rhs, WhichComparison );     } 

The Employee object must implement a custom version of CompareTo( ) , which takes the comparison and compares the objects accordingly :

 public int CompareTo         (         Employee rhs,         Employee.EmployeeComparer.ComparisonType whichComparison         )     {        switch (whichComparison)        {           case Employee.EmployeeComparer.ComparisonType.EmpID:              return this.empID.CompareTo(rhs.empID);           case Employee.EmployeeComparer.ComparisonType.Yrs:              return this.yearsOfSvc.CompareTo(rhs.yearsOfSvc);        }        return 0;     } 

The complete source for this example is shown in Example 14-6. The integer array has been removed to simplify the example, and the output of the employee's ToString( ) method has been enhanced to enable you to see the effects of the sort.

Example 14-6. Sorting an array by employees' IDs and years of service
 using System; using System.Collections.Generic; namespace IComparer {    public class  Employee  :  IComparable  <  Employee  >    {       private int empID;       private int yearsOfSvc = 1;       public  Employee  ( int empID )       {          this.empID = empID;       }       public  Employee  ( int empID, int yearsOfSvc )       {          this.empID = empID;          this.yearsOfSvc = yearsOfSvc;       }  public override string ToString(  )       {          return "ID: " + empID.ToString(  ) +          ". Years of Svc: " + yearsOfSvc.ToString(  );       }  public bool Equals(  Employee  other )       {          if ( this.empID == other.empID )          {             return true;          }          else          {             return false;          }       }       // static method to get a Comparer object       public static  EmployeeComparer  GetComparer(  )       {          return new  Employee  .  EmployeeComparer  (  );       }       // Comparer delegates back to Employee       // Employee uses the integer's default       // CompareTo method       public int CompareTo(  Employee  rhs )       {          return this.empID.CompareTo( rhs.empID );       }  // Special implementation to be called by custom comparer       public int CompareTo(          Employee rhs,          Employee.EmployeeComparer.ComparisonType which )       {          switch ( which )          {             case Employee.EmployeeComparer.ComparisonType.EmpID:                return this.empID.CompareTo( rhs.empID );             case Employee.EmployeeComparer.ComparisonType.Yrs:                return this.yearsOfSvc.CompareTo( rhs.yearsOfSvc );          }          return 0;       }  // nested class which implements IComparer       public class  EmployeeComparer  :  IComparer  <  Employee  >       {  // private state variable          private Employee.EmployeeComparer.ComparisonType             whichComparison;          // enumeration of comparsion types          public enum ComparisonType          {             EmpID,             Yrs          };  public  bool Equals(  Employee  lhs,  Employee  rhs )          {             return this.Compare( lhs, rhs ) == 0;          }          public  int GetHashCode(  Employee  e)          {             return e.GetHashCode(  );          }          // Tell the Employee objects to compare themselves          public int Compare(  Employee  lhs,  Employee  rhs )          {              return lhs.CompareTo( rhs, WhichComparison );          }          public  Employee  .  EmployeeComparer  .  ComparisonType  WhichComparison          {             get{return whichComparison;}             set{whichComparison = value;}          }       }    }    public class  Tester  {       static void Main(  )       {  List  <  Employee  > empArray = new  List  <  Employee  >(  );          // generate random numbers for          // both the integers and the          // employee id's  Random  r = new  Random  (  );          // populate the array          for ( int i = 0; i < 5; i++ )          {             // add a random employee id             empArray.Add(                new  Employee  (                   r.Next( 10 ) + 100, r.Next( 20 )                )             );          }          // display all the contents of the Employee array          for ( int i = 0; i < empArray.Count; i++ )          {  Console  .Write( "\n{0} ", empArray[i].ToString(  ) );          }  Console  .WriteLine( "\n" );  // sort and display the employee array          Employee.EmployeeComparer c = Employee.GetComparer(  );          c.WhichComparison =          Employee.EmployeeComparer.ComparisonType.EmpID;          empArray.Sort( c );  // display all the contents of the Employee array          for ( int i = 0; i < empArray.Count; i++ )          {  Console  .Write( "\n{0} ", empArray[i].ToString(  ) );          }  Console  .WriteLine( "\n" );  c.WhichComparison = Employee.EmployeeComparer.ComparisonType.Yrs;          empArray.Sort( c );  for ( int i = 0; i < empArray.Count; i++ )          {  Console  .Write( "\n{0} ", empArray[i].ToString(  ) );          }  Console  .WriteLine( "\n" );       }    } } 

The output looks like this for one run of the program:

 ID: 103. Years of Svc: 11     ID: 108. Years of Svc: 15     ID: 107. Years of Svc: 14     ID: 108. Years of Svc: 5     ID: 102. Years of Svc: 0     ID: 102. Years of Svc: 0     ID: 103. Years of Svc: 11     ID: 107. Years of Svc: 14     ID: 108. Years of Svc: 15     ID: 108. Years of Svc: 5     ID: 102. Years of Svc: 0     ID: 108. Years of Svc: 5     ID: 103. Years of Svc: 11     ID: 107. Years of Svc: 14     ID: 108. Years of Svc: 15 

The first block of output shows the Employee objects as they are added to the List . The employee ID values and the years of service are in random order. The second block shows the results of sorting by the employee ID, and the third block shows the results of sorting by years of service.

14.4.2. Generic Queues

A queue represents a first-in, first-out (FIFO ) collection. The classic analogy is to a line (or queue, if you are British) at a ticket window. The first person in line ought to be the first person to come off the line to buy a ticket.

A queue is a good collection to use when you are managing a limited resource. For example, you might want to send messages to a resource that can only handle one message at a time. You would then create a message queue so that you can say to your clients : "Your message is important to us. Messages are handled in the order in which they are received."

The Queue class has a number of member methods and properties, the most important of which are shown in Table 14-3.

Table 14-3. Queue methods and properties

Method or property

Purpose

Count

Public property that gets the number of elements in the Queue

Clear( )

Removes all objects from the Queue

Contains( )

Determines if an element is in the Queue

CopyTo( )

Copies the Queue elements to an existing one-dimensional array

Dequeue( )

Removes and returns the object at the beginning of the Queue

Enqueue( )

Adds an object to the end of the Queue

GetEnumerator( )

Returns an enumerator for the Queue

Peek( )

Returns the object at the beginning of the Queue without removing it

ToArray( )

Copies the elements to a new array


Add elements to your queue with the Enqueue command and take them off the queue with Dequeue or by using an enumerator, as shown in Example 14-7.

Example 14-7. Working with a queue
 using System; using System.Collections.Generic; namespace Queue {    public class  Tester  {       static void Main(  )       {  Queue  <  Int32  > intQueue = new  Queue  <  Int32  >(  );          // populate the array          for ( int i = 0; i < 5; i++ )          {             intQueue.Enqueue( i * 5 );          }          // Display the Queue.  Console  .Write( "intQueue values:\t" );          PrintValues( intQueue );          // Remove an element from the Queue.  Console  .WriteLine(             "\n(Dequeue)\t{0}", intQueue.Dequeue(  ) );          // Display the Queue.  Console  .Write( "intQueue values:\t" );          PrintValues( intQueue );          // Remove another element from the Queue.  Console  .WriteLine(             "\n(Dequeue)\t{0}", intQueue.Dequeue(  ) );          // Display the Queue.  Console  .Write( "intQueue values:\t" );          PrintValues( intQueue );          // View the first element in the          // Queue but do not remove.  Console  .WriteLine(             "\n(Peek)   \t{0}", intQueue.Peek(  ) );          // Display the Queue.  Console  .Write( "intQueue values:\t" );          PrintValues( intQueue );       }       public static void PrintValues(  IEnumerable  <  Int32  > myCollection)       {  IEnumerator  <  Int32  > myEnumerator =             myCollection.GetEnumerator(  );          while ( myEnumerator.MoveNext(  ) )  Console  .Write( "{0} ", myEnumerator.Current );  Console  .WriteLine(  );       }    } } 

The output looks like this:

 intQueue values:       0 5 10 15 20     (Dequeue)       0     intQueue values:       5 10 15 20     (Dequeue)       5     intQueue values:       10 15 20     (Peek)          10     intQueue values:       10 15 20 

I've dispensed with the Employee class to save room, but of course you can enqueue user -defined objects as well. The output shows that queuing objects adds them to the Queue , while Dequeue( ) returns the object and also removes them from the Queue . The Queue class also provides a Peek( ) method that allows you to see, but not remove, the next element.

Because the Queue class is enumerable, you can pass it to the PrintValues( ) method, which is provided as an IEnumerable interface. The conversion is implicit. In the PrintValues method, you call GetEnumerator , which you will remember is the single method of all IEnumerable classes. This returns an IEnumerator , which you then use to enumerate all the objects in the collection.

14.4.3. Generic Stacks

A Stack is a last-in, first-out (LIFO ) collection, like a stack of dishes at a buffet table, or a stack of coins on your desk. A dish added on top, is the first dish you take off the stack.

The principal methods for adding to and removing from a stack are Push( ) and Pop( ) ; Stack also offers a Peek( ) method, very much like Queue . The significant methods and properties for S tack are shown in Table 14-4.

Table 14-4. Stack methods and properties

Method or property

Purpose

Count

Public property that gets the number of elements in the Stack

Clear( )

Removes all objects from the Stack

Contains( )

Determines if an element is in the Stack

CopyTo( )

Copies the Stack elements to an existing one-dimensional array

GetEnumerator( )

Returns an enumerator for the Stack

Peek( )

Returns the object at the top of the Stack without removing it

Pop( )

Removes and returns the object at the top of the Stack

Push( )

Inserts an object at the top of the Stack

ToArray( )

Copies the elements to a new array


The List , Queue , and Stack types contain multiple versions of the CopyTo( ) and ToArray( ) methods for copying their elements to an array. In the case of a Stack , the CopyTo( ) method will copy its elements to an existing one-dimensional array, overwriting the contents of the array beginning at the index you specify. The ToArray( ) method returns a new array with the contents of the Stack 's elements. Example 14-8 illustrates several of the Stack methods.

Example 14-8. Working with a Stack
 using System; using System.Collections.Generic; namespace Stack {    public class  Tester  {       static void Main(  )       {  Stack  <  Int32  > intStack = new  Stack  <  Int32  >(  );          // populate the array          for ( int i = 0; i < 8; i++ )          {             intStack.Push( i * 5 );          }          // Display the Stack.  Console  .Write( "intStack values:\t" );          PrintValues( intStack );          // Remove an element from the Stack.  Console  .WriteLine( "\n(Pop)\t{0}",          intStack.Pop(  ) );          // Display the Stack.  Console  .Write( "intStack values:\t" );          PrintValues( intStack );          // Remove another element from the Stack.  Console  .WriteLine( "\n(Pop)\t{0}",             intStack.Pop(  ) );          // Display the Stack.  Console  .Write( "intStack values:\t" );          PrintValues( intStack );          // View the first element in the          // Stack but do not remove.  Console  .WriteLine( "\n(Peek)   \t{0}",             intStack.Peek(  ) );          // Display the Stack.  Console  .Write( "intStack values:\t" );          PrintValues( intStack );          // Declare an array object which will          // hold 12 integers          int[] targetArray = new int[12];          for (int i = 0; i < targetArray.Length; i++)          {              targetArray[i] = i * 100 + 100;          }          // Display the values of the target Array instance.  Console  .WriteLine( "\nTarget array:  " );          PrintValues( targetArray );          // Copy the entire source Stack to the          // target Array instance, starting at index 6.          intStack.CopyTo( targetArray, 6 );          // Display the values of the target Array instance.  Console  .WriteLine( "\nTarget array after copy:  " );          PrintValues( targetArray );       }       public static void PrintValues(  IEnumerable  <  Int32  > myCollection )       {  IEnumerator  <  Int32  > enumerator =             myCollection.GetEnumerator(  );          while ( enumerator.MoveNext(  ) )  Console  .Write( "{0}  ", enumerator.Current );  Console  .WriteLine(  );       }    } } 

The output looks like this:

 intStack values:        35  30  25  20  15  10  5  0     (Pop)   35     intStack values:        30  25  20  15  10  5  0     (Pop)   30     intStack values:        25  20  15  10  5  0     (Peek)          25     intStack values:        25  20  15  10  5  0     Target array:     100  200  300  400  500  600  700  800  900  1000  1100  1200     Target array after copy:     100  200  300  400  500  600  25  20  15  10  5  0     The new  array:     25  20  15  10  5  0 

The output reflects that the items pushed onto the Stack were popped in reverse order.

The effect of CopyTo( ) can be seen by examining the target array before and after calling CopyTo( ) . The array elements are overwritten beginning with the index specified ( 6 ).

14.4.4. Dictionaries

A dictionary is a collection that associates a key to a value . A language dictionary, such as Webster's, associates a word (the key) with its definition (the value).

To see the value of dictionaries , start by imagining that you want to keep a list of the state capitals. One approach might be to put them in an array:

 string[] stateCapitals = new string[50]; 

The stateCapitals array will hold 50 state capitals. Each capital is accessed as an offset into the array. For example, to access the capital for Arkansas, you need to know that Arkansas is the fourth state in alphabetical order:

 string capitalOfArkansas = stateCapitals[3]; 

It is inconvenient, however, to access state capitals using array notation. After all, if I need the capital for Massachusetts, there is no easy way for me to determine that Massachusetts is the 21st state alphabetically .

It would be far more convenient to store the capital with the state name. A dictionary allows you to store a value (in this case, the capital) with a key (in this case, the name of the state).

A .NET Framework dictionary can associate any kind of key (string, integer, object) with any kind of value (string, integer, object). Typically, the key is fairly short and the value fairly complex, though in this case, we'll use short strings for both.

The most important attributes of a good dictionary are that it is easy to add values and it is quick to retrieve values. Table 14-5 lists some of the more important methods and properties of the dictionary.

Table 14-5. Dictionary methods and properties

Method or property

Purpose

Count

Public property that gets the number of elements in the Dictionary .

Item( )

The indexer for the Dictionary .

Keys

Public property that gets a collection containing the keys in the Dictionary . (See also Values , later in this table.)

Values

Public property that gets a collection containing the values in the Dictionary . (See also Keys , earlier in this table.)

Add( )

Adds an entry with a specified Key and Value .

Clear( )

Removes all objects from the Dictionary .

ContainsKey( )

Determines whether the Dictionary has a specified key.

ContainsValue( )

Determines whether the Dictionary has a specified value.

GetEnumerator( )

Returns an enumerator for the Dictionary .

Remove( )

Removes the entry with the specified Key .


The key in a Dictionary can be a primitive type, or it can be an instance of a user-defined type (an object).

Objects used as keys for a Dictionary must implement GetHashCode( ) as well as Equals . In most cases, you can simply use the inherited implementation from Object .


Dictionaries implement the IDictionary<TKey,TValue> interface (where TKey is the key type and TValue> is the value type). IDictionary provides a public property Item . The Item property retrieves a value with the specified key.

The Item property is implemented with the index operator ( [] ). Thus, you access items in any Dictionary object using the offset syntax, as you would with an array.

Example 14-9 demonstrates adding items to a Dictionary and then retrieving them with the indexer (which implicitly calls the Dictionary 's Item property).

Example 14-9. The Item property as offset operators
 using System; using System.Collections.Generic; namespace Dictionary {    public class Tester    {       static void Main(  )       {          // Create and initialize a new Dictionary.          Dictionary<string, string>  dict  =            new Dictionary<string, string>(  );       dict.Add("Alabama", "Montgomery");       dict.Add("Alaska", "Juneau");       dict.Add("Arizona", "Phoenix");       dict.Add("Arkansas", "Little Rock");       dict.Add("California", "Sacramento");       dict.Add("Colorado", "Denver");       dict.Add("Connecticut", "Hartford");       dict.Add("Delaware", "Dover");       dict.Add("Florida", "Tallahassee");       dict.Add("Georgia", "Atlanta");       dict.Add("Hawaii", "Honolulu");       dict.Add("Idaho", "Boise");       dict.Add("Illinois", "Springfield");       dict.Add("Indiana", "Indianapolis");       dict.Add("Iowa", "Des Moines");       dict.Add("Kansas", "Topeka");       dict.Add("Kentucky", "Frankfort");       dict.Add("Louisiana", "Baton Rouge");       dict.Add("Maine", "Augusta");       dict.Add("Maryland", "Annapolis");       dict.Add("Massachusetts", "Boston");       dict.Add("Michigan", "Lansing");       dict.Add("Minnesota", "St. Paul");       dict.Add("Mississippi", "Jackson");       dict.Add("Missouri", "Jefferson City");       dict.Add("Montana", "Helena");       dict.Add("Nebraska", "Lincoln");       dict.Add("Nevada", "Carson City");       dict.Add("New Hampshire", "Concord");       dict.Add("New Jersey", "Trenton");       dict.Add("New Mexico", "Santa Fe");       dict.Add("New York", "Albany");       dict.Add("North Carolina", "Raleigh");       dict.Add("North Dakota", "Bismarck");       dict.Add("Ohio", "Columbus");       dict.Add("Oklahoma", "Oklahoma City");       dict.Add("Oregon", "Portland");       dict.Add("Pennsylvania", "Harrisburg");       dict.Add("Rhode Island", "Providence");       dict.Add("South Carolina", "Columbia");       dict.Add("South Dakota", "Pierre");       dict.Add("Tennessee", "Nashville");       dict.Add("Texas", "Austin");       dict.Add("Utah", "Salt Lake City");       dict.Add("Vermont", "Montpelier");       dict.Add("Virginia", "Richmond");       dict.Add("Washington", "Olympia");       dict.Add("West Virginia", "Charleston");       dict.Add("Wisconsin", "Madison");       dict.Add("Wyoming", "Cheyenne");       // access a state  Console.WriteLine( "The capital of Massachusetts is {0}",         dict["Massachusetts"] );  }      // end main    }         // end class }            // end namespace 

The output looks like this:

 The capital of Massachusetts is Boston 

Example 14-9 begins by instantiating a new Dictionary object with the type of the key and of the value declared to be string.

We add 50 key/value pairs. In this example, the state name is the key and the capital is the value (though, in a typical dictionary, the value is almost always larger than the key).

You must not change the value of the key object once you use it in a dictionary.




Learning C# 2005
Learning C# 2005: Get Started with C# 2.0 and .NET Programming (2nd Edition)
ISBN: 0596102097
EAN: 2147483647
Year: 2004
Pages: 250

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net