Collection Interfaces

Like Java, the .NET Framework declares interfaces that define the core collection functionality; these interfaces provide common functionality that can be extended to achieve specialized behavior.

A class that implements one of the collection interfaces is known as a collection class. Note that a collection class is not required to implement every interface member and may throw a NotSupportedException when unimplemented members are invoked.

All of the interfaces covered in this section are found in the System.Collections namespace.

ICollection

This is the foundation of the collections namespace and is implemented by all the collection classes. It defines only the most basic collection functionality, as shown in Table 9-1.

Table 9-1. The ICollection Interface

Member

Description

Properties

 

Count

Returns the number of items in the collection.

IsSynchronized

Returns true if this instance is thread-safe.

SyncRoot

Returns an object that can be used to provide synchronized access to the collection.

Methods

 

CopyTo()

Copies all of the elements in the collection into an array. Throws an exception if more elements are in the collection than can be held in the array or if the elements cannot be implicitly cast to the array type.

The equivalent Java interface is java.util.Collection, containing 15 methods that provide commonality across all collection classes. .NET takes the approach of pushing method definitions down into specialized interfaces for lists and dictionaries.

IEnumerable, IEnumerator, and the foreach Keyword

The IEnumerable interface is very simple but useful. It contains only one method:

IEnumerator.GetEnumerator();

Classes that implement this method must return a class that implements the IEnumerator interface. The IEnumerator interface defines the notion of a cursor that moves over the elements of a collection. It has three members, as described in Table 9-2, for moving the cursor and retrieving elements from the collection.

Table 9-2. The IEnumerator Interface

Member

Comments

Properties

 

Current

The Current property returns the element at the position of the cursor. The type that is returned is determined by the implementation, but the return type is defined as object.

Methods

 

MoveNext()

By default, the cursor is positioned before the first element in the enumeration. The MoveNext method advances the cursor returning true if the cursor was successfully advanced to the next element and false if the cursor has moved past the last element. The first call to MoveNext should position the cursor at the first collection element.

In common with Java, .NET enumerators are not thread safe, and when implementing IEnumerator, take care to provide a copy of the elements or to ensure that modifications cannot be made to the underlying data while the enumerator is in use.

The following example demonstrates use of IEnumerator and IEnumerable:

using System ;
using System.Collections ;
class EnumExample : IEnumerator {
    private object[] o_arr;
    private int o_cursor;

    public EnumExample(object[] p_arr) {
        o_arr = p_arr;
        o_cursor = -1;
    }

    public object Current {
        get {
            if (o_cursor > -1 && o_cursor < o_arr.Length) {
                return o_arr[o_cursor];
            } else {
                throw new InvalidOperationException();
            }
        }
    }

    public bool MoveNext() {
        o_cursor++;
        return o_cursor < o_arr.Length;
     }

    public void Reset() {
        o_cursor = -1;
    }
}

Here’s a fragment that demonstrates using the EnumExample class, iterating over a string array:

EnumExample x_example = new EnumExample(
    new string[] {"allen", "jones", "adam", "freeman"});

    while (x_example.MoveNext()) {
        Console.WriteLine("Element: " +
            x_example.Current.ToString());
    }
}

And here’s the output:

Element: allen
Element: jones
Element: adam
Element: freeman

We can use the IEnumerator implementation to provide support for an IEnumerable implementation. In this example, we pass the underlying array into the enumerator.

class Enumerator : IEnumerable {
    private object[] o_array;

    public Enumerator(object[] p_arr) {
        o_array = p_arr;
    }

    public IEnumerator GetEnumerator() {
        return new EnumExample(o_array);
    }
}

To get hold of the enumerator, a call is made to the GetEnumerator method.

Any class that implements the IEnumerable interface can be iterated over using the foreach statement, which provides a clean syntax when iterating over collections. Unfortunately, the foreach statement provides no mechanism to access the index of the element being worked with. If index access is a requirement, we suggest using a for loop.

More Info

You can find a full discussion of both the foreach and for statements in Chapter 4.

IComparer and IComparable

Like Java, .NET defines two interfaces used to sort collections. One is for classes that will make comparisons and the other for classes that will be compared; these are similar to the Java interfaces for sorting. .NET defines the interface System.IComparable, which is a direct equivalent of java.lang.Comparable. Both the Java and .NET interfaces define a single method that takes an object argument. The return value is an int stating the relative rank of the IComparable to the object argument. The second interface is System.Collections.IComparer, implemented by classes that are able to sort the elements of a collection. The only method in this interface is Compare, which takes two object arguments and returns their rankings.

Most of the fundamental classes implement IComparable, including the struct implementations of all simple value types, making sorting with simple types straightforward. .NET provides two utility classes that can be used to assist with simple sorting. These are System.Collection.Comparer and System.Collection.CaseInsensitiveComparer. These classes are used in conjunction with sorting routines such as those implemented by System.Array. Here’s an example:

string[] x_arr = new string[] {"Allen", "Jones",
                    "Adam", "Freeman"};
Array.Sort(x_arr, Comparer.Default);

foreach (string x_str in x_arr) {
    Console.WriteLine("STR: " + x_str);
}

The output follows:

STR: Adam
STR: Allen
STR: Freeman
STR: Jones

Instances of both comparers are obtained using their static Default field and are not constructed directly. The single instance can be shared between sorting operations in different threads and classes.

Other Collection Interfaces

Two other collection interfaces are worth noting: IList and IDictionary. These provide the foundation for indexed array collections (such as ArrayList) and key/value collections (such as Hashtable). We’ll discuss the classes that implement these interfaces in the next section.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset