|
Creating
efficient data structures has always been a nightmare for
programmers. But while writing a C# program, how to build
a data structure is the last thing on ones mind. The
.NET Foundation Class Library contains a namespace called
System.Collections that provides classes to manage data structures
like arrays, lists and maps. It also provides interfaces to
enumerate and compare the elements of collections.
Let us first discuss in brief the classes available for maintaining
the above-mentioned data structures.
The ArrayList class is similar to the Array class except that
its size can grow dynamically. Like the Array class, the ArrayList
class contains various methods to perform functions like adding,
inserting, removing, copying, etc. The Queue and Stack classes
provide the First In First Out and Last
In First Out types of collections respectively.
The
base class library provides a class called BitArray that allows
the creation of an unusual arrayan array of bits. If
we provide an int array, the bits array gets created with
the bit values of every element of the array. The Hashtable
and SortedList classes manage a collection of key-value pairs.
The difference between the Hashtable and SortedList class
is that in the SortedList class, the values are sorted by
keys and are accessible by key as well as by index.
Using these classes is straightforward and is dealt with in
enough detail in several popular C# books. We simply have
to instantiate an object of the relevant collection class
and call its methods. The difficult program logic comes into
the picture when we have to provide collection support to
our class. Let us see what collection support means.
A collection is a set of the same type of objects that are
grouped together and that is able to supply a reference to
an enumerator. An enumerator is an object that iterates through
its associated collection. It can be thought of as a movable
pointer pointing to any element in the collection. In order
to provide an enumerator, a class must implement the IEnumerable
interface. If a class implements IEnumerable interface, we
can use an object of the class in foreach statement. We will
now see an example that shows how to provide enumeration support
to our class.
We will write a class sample having an int array named arr
as a data member. The sample class would implement the IEnumerable
interface so that we can enumerate through the array arr using
the foreach statement. Here is the code.
using System;
using System.Collections;
class sample : IEnumerable
{
int[ ] arr = { 10, 11, 12, 13, 14 };
class myenumerator : IEnumerator
{
int c;
sample s;
public myenumerator ( sample ss )
{
c = -1;
s = ss;
}
public object Current
{
get
{
return s.arr [ c ];
}
}
public bool MoveNext( )
{
if ( c < s.arr.Length - 1 )
{
c++;
return true;
}
else
return false;
}
public void Reset( )
{
c = -1;
}
}
public IEnumerator GetEnumerator( )
{
return new myenumerator ( this );
}
}
The IEnumerable interface declares only one method GetEnumerator(
). The GetEnumerator( ) method returns reference to the enumerator
object. We have to write our own enumerator so that it would
enumerate our collection. To create an enumerator we have
to write a class that implements the IEnumerator interface.
Here our enumerator class is myenumerator.
In the GetEnumerator( ) method we have created an object of
myenumerator class and passed to its constructor the this
reference. This is necessary because we have to access arr
in the methods of myenumerator class. We have implemented
the methods of IEnumerator interfaceMoveNext( ) and
Reset( ) and a property called Current.
Let us now understand how an enumerator works. When an enumerator
object is initialised, it does not point to any element of
the collection. We must call the MoveNext( ) method that moves
the enumerator to the first element of the collection. We
can retrieve this element by calling the Current property.
We can do whatever we want with this element. Then we must
move to the next element by calling the MoveNext( ) method
again. If we want to enumerate the collection again we can
call the Reset( ) method that returns before the beginning
of collection.
Our implementation of MoveNext( ), Reset( ) and Current does
the same.
Now, we can use the foreach statement on an object of the
class sample as shown below.
sample s = new sample( ) ;
foreach ( int i in s )
Console.WriteLine ( i ) ;
The foreach statement works like this.
IEnumerator e = s.GetEnumerator( ) ;
while ( e.MoveNext( ) )
Console.WriteLine ( e.Current ) ;
The foreach statement would terminate when the MoveNext( )
method would return false.
Note that it is necessary to design a separate class implementing
the IEnumerator interface rather than implementing it in the
collection class itself. If we implement the IEnumerator interface
in the collection class, we would face a problem when enumerating
the same object again.
 |
Yashavant
Kanetkar, one of the first Express Computer columnists,
is an established software expert, speaker and author
with several best-sellers to his credit, including titles
like “Let Us C” and the “Fundas” series. Contact him at
kanet@nagpur.dot.net.in |
|