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.
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 |
---|---|
| Property to get or set the number of
elements the |
| Property to get the number of elements currently in the list. |
| Gets or sets the element at the
specified index. This is the indexer for the |
| Public method to add an object to
the |
| Public method that adds the elements
of an |
| Overloaded public method that uses a
binary search to locate a specific element in a sorted
|
| Removes all elements from the
|
| Determines if an element is in the
|
| Overloaded public method that copies
a |
Exists( ) | Determines if an element is in the
|
Find( ) | Returns the first occurrence of the
element in the |
FindAll( ) | Returns all the specified elements
in the |
| Overloaded public method that
returns an enumerator to iterate through a |
| Copies a range of elements to a new
|
| Overloaded public method that returns the index of the first occurrence of a value. |
| Inserts an element into |
| Inserts the elements of a collection
into the |
| Overloaded public method that
returns the index of the last occurrence of a value in the
|
| Removes the first occurrence of a specific object. |
| Removes the element at the specified index. |
| Removes a range of elements. |
| Reverses the order of elements in
the |
| Sorts the |
| Copies the elements of the |
| Sets the capacity to the actual
number of elements in the |
[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( " " ); // print all the contents of the Employee List for ( int i = 0; i < empList.Count; i++ ) { Console.Write( "{0} ", empList[i].ToString( ) ); } Console.WriteLine( " " ); 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.
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 0
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
0
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 classEmployee : IComparable<Employee>
{ private int empID; publicEmployee
( 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 classTester
{ static void Main( ) { List<Employee> empList = new List<Employee>( );List
<Int32
> intList = newList
<Int32
>( ); // generate random numbers for // both the integers and the // employee id'sRandom
r = newRandom
( ); // populate the array for ( int i = 0; i < 5; i++ ) { // add a random employee id empList.Add( newEmployee
( 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( " " ); // 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( " " ); // 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( " " ); // 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( " " ); } } }
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.
When you call Sort( )
on the List
in Example 14-5, the default
implementation of IComparer
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 classEmployee
:IComparable
<Employee
> { private int empID; private int yearsOfSvc = 1; publicEmployee
( int empID ) { this.empID = empID; } publicEmployee
( 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 staticEmployeeComparer
GetComparer( ) { return newEmployee
.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 classEmployeeComparer
: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 ); } publicEmployee
.EmployeeComparer
.ComparisonType
WhichComparison { get{return whichComparison;} set{whichComparison = value;} } } } public classTester
{ static void Main( ) {List
<Employee
> empArray = newList
<Employee
>( ); // generate random numbers for // both the integers and the // employee id'sRandom
r = newRandom
( ); // populate the array for ( int i = 0; i < 5; i++ ) { // add a random employee id empArray.Add( newEmployee
( 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( " {0} ", empArray[i].ToString( ) ); }Console
.WriteLine( " " ); // 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( " {0} ", empArray[i].ToString( ) ); }Console
.WriteLine( " " ); c.WhichComparison = Employee.EmployeeComparer.ComparisonType.Yrs; empArray.Sort( c ); for ( int i = 0; i < empArray.Count; i++ ) {Console
.Write( " {0} ", empArray[i].ToString( ) ); }Console
.WriteLine( " " ); } } }
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.
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 |
---|---|
| Public property that gets the number
of elements in the |
| Removes all objects from the
|
| Determines if an element is in the
|
| Copies the |
| Removes and returns the object at
the beginning of the |
| Adds an object to the end of the
|
| Returns an enumerator for the
|
| Returns the object at the beginning
of the |
| 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 classTester
{ static void Main( ) {Queue
<Int32
> intQueue = newQueue
<Int32
>( ); // populate the array for ( int i = 0; i < 5; i++ ) { intQueue.Enqueue( i * 5 ); } // Display the Queue.Console
.Write( "intQueue values: " ); PrintValues( intQueue ); // Remove an element from the Queue.Console
.WriteLine( " (Dequeue) {0}", intQueue.Dequeue( ) ); // Display the Queue.Console
.Write( "intQueue values: " ); PrintValues( intQueue ); // Remove another element from the Queue.Console
.WriteLine( " (Dequeue) {0}", intQueue.Dequeue( ) ); // Display the Queue.Console
.Write( "intQueue values: " ); PrintValues( intQueue ); // View the first element in the // Queue but do not remove.Console
.WriteLine( " (Peek) {0}", intQueue.Peek( ) ); // Display the Queue.Console
.Write( "intQueue values: " ); 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.
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 Stack
are shown in
Table 14-4.
Table 14-4. Stack methods and properties
Method or property | Purpose |
---|---|
| Public property that gets the number
of elements in the |
| Removes all objects from the
|
| Determines if an element is in the
|
| Copies the |
| Returns an enumerator for the
|
| Returns the object at the top of the
|
| Removes and returns the object at
the top of the |
| Inserts an object at the top of the
|
| 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 classTester
{ static void Main( ) {Stack
<Int32
> intStack = newStack
<Int32
>( ); // populate the array for ( int i = 0; i < 8; i++ ) { intStack.Push( i * 5 ); } // Display the Stack.Console
.Write( "intStack values: " ); PrintValues( intStack ); // Remove an element from the Stack.Console
.WriteLine( " (Pop) {0}", intStack.Pop( ) ); // Display the Stack.Console
.Write( "intStack values: " ); PrintValues( intStack ); // Remove another element from the Stack.Console
.WriteLine( " (Pop) {0}", intStack.Pop( ) ); // Display the Stack.Console
.Write( "intStack values: " ); PrintValues( intStack ); // View the first element in the // Stack but do not remove.Console
.WriteLine( " (Peek) {0}", intStack.Peek( ) ); // Display the Stack.Console
.Write( "intStack values: " ); 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( " Target 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( " Target 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
).
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 |
---|---|
| Public property that gets the number
of elements in the |
| The indexer for the |
| Public property that gets a
collection containing the keys in the |
| Public property that gets a
collection containing the values in the |
| Adds an entry with a specified
|
| Removes all objects from the
|
| Determines whether the |
| Determines whether the |
| Returns an enumerator for the
|
| Removes the entry with the specified
|
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).