Last Updated:

Collection interfaces

Now, having discussed the concept of interfaces in sufficient detail, we can take a closer look at the collections, in particular, the ArrayList class, which we actively used in the Acme Travel Agency program. If you look closely at the definition of the ArrayList class, you can see that it implements four standard interfaces.

// garbage collector class ArrayList
_gс class ArrayList: public IList, ICollection,
lEnumerable, ICloneable

The first three form a simple hierarchical structure, shown in Fig. 5.1. When moving through the structure, additional methods appear in the interfaces, and, finally, IList has the most complete set of them.

collection interface

Fig. 5.1. Interface hierarchy for lists

The fourth interface implemented in the ArrayList, ICloneable, is independent of the first three and is designed to perform detailed copying of objects. To familiarize yourself with the interfaces that allow you to work with collections, consider the StringList program. Review the main Main method of the StringList program, and the helper methods will be discussed in detail as we become familiar with the different interfaces for working with collections.

//StringList.h
_gc class StringList
// garbage collector class StringList
{
private: // private
static ArrayList *pList; // static
public:
static void Main() // static Main
{
// Initialize strings and show initial state
pList = new ArrayList(4);
ShowCount();
AddStringC'Amy"); // Amy
AddStringC'Bob"); // Bob
AddString("Charlie"}; // Charlie
ShowEnum(pList);// counter
ShowCount();
// Add two more lines and show the state again
AddString("David"); //David
AddString("Ellen"); // Ellen
ShowList(pList); // simulate
foreach ShowCount(};
// Remove two lines from the list and show the state
RemoveString("David"); // David RemoveAt(0);
ShowArray(pList);// index entry ShowCount();
// Attempt to remove two lines that are not in the list
RemoveString("Amy"); // Amy
RemoveAt(3);
}
private: // private
static void ShowEnum(ArrayList *pArray) // static function
{
lEnumerator *plter = pArray › GetEnumerator();
bool more = p!ter › MoveNext();
while (more)
{
String *pStr =
dynamic_cast<String *>((p!ter › Current));
Console::WriteLine(pStr);
more = p!ter › MoveNext();
}
}

 

static void ShowList(ArrayList *pArray) // static function
{
lEnumerator *pEnum =
pArray › GetEnumerator();
while (pEnum › MoveNext())
{
String *pStr =
dynamic_cast<String *>(pEnum › Current);
Console::WriteLine(pStr};
}
}
static void ShowArray(ArrayList *pArray) // static function
{
for (int i = 0; i < pArray › Count; i++) f
Console::WriteLine(
"pArray › get_Item({0}) = {!}", _box(i),
pArray › get_Item(i)); } }
static void ShowCount() // static function
{
Console::WriteLine(
"pList › Count = {0}", _box(pList › Count));
Console::WriteLine(
"pList › Capacity = {0}", _box(pList › Capacity));
// Capacity
}
static void AddString (String *pStr) // static function
{
if (pList › Contains(pStr)) // if contains throw new Exception!
// new Exception
String::Format("list contains {0}", pStr)); // Format: list contains
pList › Add(pStr); // Add
}
static void RemoveString(String *pStr) // static function
{
if (pList › Contains(pStr)) // if contains
pList › Remove(pStr); // Delete else
Console::WriteLine(
"List does not contain {0}", pStr); // List
//does not contain
}
static void RemoveAt(int nlndex) // static function
{
try // attempt
{
pList › RemoveAt(nlndex);
}
catch(ArgumentOutOfRangeException*)
{
Console::WriteLine(
"No element at index {0}", _box(nlndex));
// No element with this index
}
}
};

The result of the program will be as follows:

pList › Count = 0
pList › Capacity = 4 // Capacity
Amy // Amy
Bob // Bob
Charlie // Charlie
pList › Count = 3
pList › Capacity =4 // Capacity
Amy // Amy
Bob // Bob
Charlie // Charlie
David // David
Ellen // Ellen
pList › Count = 5
pList › Capacity =8 // Capacity
pArray › get_Item(0) = Bob // Bob
pArray › get_Item(1) = Charlie // Charlie
pArray › get_Item(2) = Ellen // Ellen
pList › Count = 3
pList › Capacity =8 // Capacity
List does not contain Amy
No element at index 3 // No element at index 3

 

lEnumerable and JEnumerator

The starting point for all interfaces designed to work with collections is the lEnumerable interface, which has one method, GetEnumerator.

_gc_interface lEnumerable
// garbage collector - lEnumerable
{
lEnumerator* GetEnumerator();
};

GetEnumerator returns a pointer to the lEnumerator interface, which is used to sequentially access the items in the collection. This interface has a Current property and the MoveNext and Reset methods.

_gc_interface lEnumerator
// garbage collector - lEnumerator
{
_property Object* get__Current();
bool MoveNext(); // logical (boolean)
void reset();
};

Immediately after initialization, the numberer indicates the position in front of the first element of the collection and, therefore, to gain access to even the first element of it, it must be promoted. Using a numberer to access list items sequentially is illustrated in the ShowEnum method.

static void ShowEnum(ArrayList *pArray) // static function
{
lEnumerator *plter =
pArray › GetEnumerator();
bool more = peter › MoveNext(); // boolean value while (more)
{
String *pStr =
dynamic_cast<String *>((p!ter › Current));
Console::WriteLine(pStr);
more = p!ter › MoveNext();
}
}

ICollection Interface

The ICollection interface derives from lEnumerable and adds the Count property and the CopyTo method.

_gc_interface ICollection: public lEnumerable
// garbage collector - ICollection: lEnumerable
{
_property int get_Count();
_property bool get_IsSynchronized(); // boolean
_property Object* get_SyncRoot();
void CopyTo(Array* array, int index); // array, index
};

In addition, properties appear in this interface that are designed to provide synchronization when threads are used. "Is it safe to use threads?" is one of the frequently asked questions about any library. As for the .NET Framework, the answer to this question is short and clear– no. That's not to say that .NET Framework developers haven't thought about threading security. On the contrary, they have implemented many mechanisms that can help you when working with threads.

The reason why using threads when working with collections is not automatically secure is that security leads to a decrease in performance, and if it is provided automatically, then when working in single-threaded mode, performance will be underestimated. If you need to ensure security when working with threads, you can use the interface properties designed for synchronization. The mechanisms for synchronizing threads in the .NET Framework will be discussed in more detail in Chapter 8, ".NET Framework Wireframe Classes."

StringList illustrates the use of the Capacity property of the ArrayList class and the Count property inherited by the ArrayList class from the ICollection interface.

static void ShowCount() // static function
{
Console::WriteLine(
"pList › Count = {0}", _box(pList › Count)); // Check
Console::WriteLine(
"pList › Capacity = {0}", _box(pList › Capacity));
// Capacity
}

 

IList Interface

The IList interface derives from the iCollection interface and introduces methods for adding an item to a list, removing it from a list, and so on.

_gc_interface IList: public ICollection
// garbage collector - IList: ICollection
{
_property bool get_IsFixedSize(); // boolean
_property bool get_IsReadOnly(); // boolean
_property Object* get_Item(int index); // index
_property void set_Item(int index, Object*); // index,
// An object *
int Add(0bject*value); // Add value
voidClear();
bool Contains(Object* value); // Does it contain a value
int IndexOf(Object* value); // meaning
void Insert(int index, Object* value); // Insert (int index,
// Object* value);
void Remove(Object* value); // Remove value
void RemoveAt(int index); // index };

The stringList program demonstrates the use of the get_Item indexer and the ContainsAddRemove, and RemoveAt methods.

static void ShowArray(ArrayList *pArray)
{
for (int i = 0; i < pArray › Count; i++)
{
Console::WriteLine(
"pArray › get_Item({0}) = {!}", _box(i),
pArray › get_Item(i));
}
}
static void AddString(String*pStr)
{
if (pList › Contains(pStr))
// if contains throw new Exception(
// new Exception
String::Format("list contains {0}", pStr));
// Format:: ("list contains")
pList › Add(pStr); // Add
}
i static void RemoveString(String *pStr)
{
if (pList › Contains(pStr)) // if contains
pList › Remove(pStr); // Delete
else
Console::WriteLine(
"List does not contain {0}", pStr); // List
// does not contain
}
static void RemoveAtfint nlndex)
{
try // attempt
{
pList › RemoveAt(nIndex);
}
catch(ArgumentOutOfRangeException*)
{
Console::WriteLine(
"No element at index {0}", _box(nlndex)); // No element
//with index
}
}