|A complete PDF version of the text book is now available. The PDF version is an almost complete subset of the HTML version (where only a few, long program listings have been removed). See here.|
This is a short chapter in which we discuss the non-generic collection classes. You may encounter use of these classes in many older C# programs. In Section 44.1 these collection classes were called first generation collection classes.
47.1. The non-generic collection library in C#
Contents Up Previous Next Slide Annotated slide Aggregated slides Subject index Program index Exercise index
The overview of the non-generic collection interfaces and classes in Figure 47.1 is a counterpart to the sum of Figure 45.1 and Figure 46.1. The white boxes represent interfaces and the grey boxes represent classes. Most classes and interfaces shown in Figure 46.1 belong to the namespace System.Collections.
The non-generic collection classes store data of type Object
As the most important characteristics, the elements of the lists are of type Object. Both keys and values of dictionaries are Objects. Without use of type parametrization, there are no means to constraint the data in collections to of a more specific type. Thus, if we for instance work with a collection of bank accounts, we cannot statically guarantee that all elements of the collection are bank accounts. We may accidentally insert an object of another type. We will find the error at runtime. Most likely, an exception will be raised when we try to cast an Object to BankAccount.
|Figure 47.1 The class and interface inheritance tree related to collections|
The IEnumerable, ICollection, IList and IDictionary interfaces of Figure 47.1 are natural counterparts to the generic interfaces IEnumerable<T>, ICollection<T>, IList<T> and IDictionary<K,V>.
The class ArrayList corresponds to List<T>. As such, ArrayList is a class with a rich repertoire of operations for searching, sorting, and range operations. ArrayList is undoubtedly the most widely used collection class in C# 1.0 programs.
The Array class shown next to ArrayList in Figure 47.1 deserves some special clarification. It belongs to the System namespace. You cannot instantiate class Array in your programs, because Array is an abstract class. And you cannot use Array as a superclass of one of your own classes. So, class Array seems pretty useless. At least it is fair to state the class Array is rather special compared to the other classes in Figure 47.1.
Let us now explain the role of class Array. As mentioned earlier, see Section 28.2 , class Array acts as the superclass of all "native" array types in C#. (See the discussion of arrays in Section 6.4). Consequently, all the nice operation in System.Array can be used on all "native" arrays that you use in your C# programs. If, for instance, we have the array declarations
int ia = new int; string sa = new string[5,6]; BankAccount baa = new BankAccount;
the following are legal expressions
ia.Length a.Rank Array.BinarySearch(ia, 5) Array.Find(sa, IsPalindrome) Array.Sort(baa)
In the Array class, you should pay attention to the (overloaded) static method CreateInstance, which allows for programmatic creation on an arbitrary array. The Array instance methods GetValue and SetValue allow us to access elements in arbitrary arrays - independent of element type and rank.
When we talk about "native arrays" in C# we refer to the array concept implemented in the language as such. The compiler provides special support for these native arrays. In contrast, generic and non-generic collections are provided via the class library. The C# compiler and the C# interpreter do not have particular knowledge or support of the collection classes. We could have written these classes ourselves! It is interesting to notice that the native arrays, as derived from class Array in Figure 47.1, are type safe. The type safeness of native arrays is due to the special support by the compiler, which allows for declaration of the element types of the arrays (see the examples of int, string, and BankAccount arrays above).
The class HashTable in Figure 47.1 corresponds to the generic class Dictionary<K,V>, see Section 46.3 and Section 46.4).
The class ListDictionary, which belongs to the namespace System.Collections.Specialized, has no natural generic counterpart. ListDictionary is based on linear search in an unordered collection of key/value pairs. ListDictionary should therefore only be used for small dictionaries.
As the name suggests, class SortedList corresponds to SortedList<K,V>. Both rely on a (linear) list representation, sorted by keys.
The class BitArray is - by nature - a non-generic collection class. The binary digit 1 is represented as boolean true, and the binary digit 0 is represented as boolean false. BitArray provides a compact representation of a bit arrays. In the context of indexers, see Program 19.4, we have earlier discussed a partial reproduction of the class BitArray.
In addition to the types shown in Figure 47.1 there exist some specialized collections in the namespace System.Collections.Specialized. As an example, the class StringCollection is a collection of strings. The class CollectionBase in the namespace System.Collection is intended as the superclass of new, specialized collection classes. In the documentation of this class, an example shows how to define an Int16Collection as a subclass of CollectionBase. Needless to say, all these classes are obsolete relative to both C#2.0 and C#3.0. As of today, the classes may be necessary for backward compatibility, but, unfortunately, they also add to the complexity of the .NET class libraries.