Arrays are the most popular kind of collection. However, the .NET FCL offers a variety of other collections with different semantics. Collections are abstractions of data algorithms. ArrayList abstracts a dynamic array; the Stack collection abstracts a stack data structure; the Queue collection abstracts queues; the Hashtable collection abstracts a lookup table; and so on. Each collection exposes both unique and standard interfaces. The unique interface is specific to the collection type. For example, the Stack type has pop and push methods, whereas the Queue type has Dequeue and Enqueue methods. In addition, collections implement the ICollection, IEnumerable, and ICloneable interfaces. (These interfaces were described earlier in this chapter in separate sections specific to each interface.) The non-generic collection classes are implemented in the System.Collections namespace. For similar solutions to arrays, lists, and dictionaries, generic collections are preferred to non-generic and are implemented in System.Collections.Generic. Generics are detailed in Chapter 7.
Table 5-5 lists the non-generic collections in the .NET FCL.
Table 5-5. Collection types
Class | Description |
---|
ArrayList | Dynamic array |
BitArray | Bit array |
Hashtable | Lookup table of keys and values |
Queue | First-in/first-out (FIFO) collection of elements |
SortedList | Sorted list of elements |
Stack | Last-in/first-out (LIFO) collection of elements |
What follows is a detailed explanation of each collection found in the Collections namespace. The explanations are complemented with sample code that highlights the uniqueness and strength of each collection. In addition to the listed member functions, many of the collections also support these extension methods: Queryable.AsQueryable, Enumerable.Cast, and Enumerable.OfType. These extension methods are explained in Chapter 7.
An array list is a dynamic array. While a conventional array has a fixed number of elements, elements can be added or deleted at run time with a dynamic array. ArrayList elements are accessible using the indexing operator and indices.
In addition to the standard collection interfaces, ArrayList also implements the IList interface.
Table 5-6 lists the ArrayList-specific methods and properties. The static members of ArrayList are thread-safe, whereas instance members are not.
Table 5-6. ArrayList members
Member | Syntax |
---|
Constructor
The ArrayList constructor is overloaded. These are the overloaded constructors. | ArrayList()
ArrayList(
ICollection sourceCollection)
ArrayList(int capacity) |
Adapter
This method creates a wrapper ArrayList from an IList collection. | static ArrayList Adapter(
IList list) |
Add
This method adds an element to the end of the ArrayList collection. | virtual int Add(object value) |
AddRange
This method adds a range of elements to the ArrayList collection. The additional elements are received from any type that implements the ICollection interface. | virtual void AddRange(
ICollection elements) |
BinarySearch
This method performs a binary search for a specific value in a sorted ArrayList collection. The sort is controlled by the IComparable interface. | virtual int BinarySearch(
object value)
virtual int BinarySearch(
object value,
IComparer comparer)
virtual int BinarySearch(
int index,
int count,
object value,
IComparer comparer) |
Capacity
This property gets or sets the number of elements allowed in the collection. Capacity is different from the actual number of elements. The capacity is the number of elements the ArrayList can store. The capacity is increased automatically as elements are added. When the number of elements exceeds the current capacity, the capacity doubles. You can use the capacity to improve the memory management of elements in a collection. | virtual int Capacity {
get; set; } |
Clear
This method removes all the elements of the collection. | virtual void Clear() |
Contains
This method returns true if the specified element is found in a collection. If the element is not found, it returns false. | virtual bool Contains(object item) |
Count
This property returns the number of elements in the collection. | virtual int Count {
get; } |
FixedSize
This method returns a fixed-sized version of the collection parameter. | static ArrayList FixedSize(
ArrayList sourceArray)
static IList FixedSize(
IList sourceList) |
GetRange
This method returns a span of elements from the current array list. The result is returned as an ArrayList. | virtual ArrayList GetRange(
int index, int count) |
IndexOf
This method returns the index of the first matching element in the collection. | virtual int IndexOf(
object value)
virtual int IndexOf(object value,
int startIndex)
virtual int IndexOf(object value,
int startIndex,
int count) |
Insert
This method inserts an element into the collection at the specified index. | virtual void Insert(int index,
object value) |
InsertRange
This method inserts multiple elements into the collection at the specified index. | virtual void InsertRange(
int index,
ICollection sourceCollection) |
IsFixedSize
This property returns true if the collection is of fixed length. Otherwise, the property returns false. | virtual bool IsFixedSize {
get; } |
IsReadOnly
This property returns true if the collection is read-only. Otherwise, the property returns false. | virtual bool IsReadOnly {
get; } |
Item
This property gets or sets the value of the element at the index. | virtual object this[int index] {
get; set; } |
LastIndexOf
This method returns the index of the last matching element in the collection. | virtual int LastIndex(
object value)
virtual int LastIndexOf(object value,
int startIndex)
virtual int LastIndexOf(object value,
int startIndex,
int count) |
ReadOnly
This method creates a read-only wrapper for an IList object. | static ArrayList ReadOnly(
ArrayList sourceArray)
static IList ReadOnly(
IList sourceList) |
Remove
This method removes the first element in the collection that matches the value. | virtual void Remove(
object value) |
RemoveAt
At the specified index, this method removes the element from the collection. | virtual void RemoveAt(
int index) |
RemoveRange
This method removes a range of elements from a collection. | virtual void RemoveRange(
int index,
int count) |
Repeat
This method returns an ArrayList with each element initialized to the specified value. Count is the number of elements in the returned ArrayList. | static ArrayList Repeat(
object value,
int count) |
Reverse
This method reverses the order of elements in the collection. | virtual void Reverse()
virtual void Reverse(
int beginIndex,
int endingIndex) |
SetRange
This method copies elements from the source collection over the same elements in the current collection. The copy starts at the index. | virtual void SetRange(
int index,
ICollection sourceCollection) |
Sort
This method sorts an ArrayList. The sort is controlled by the IComparable interface of the element types. | virtual void Sort()
virtual void Sort(
IComparer comparer)
virtual void Sort(int index,
int count,
IComparer comparer) |
Synchronized
This method returns a thread-safe wrapper of an ArrayList or IList object. | static ArrayList Synchronized(
ArrayList sourceArray)
static IList Synchronized(
IList sourceList) |
ToArray
This method copies the current array. The Type parameter specifies the target type of the array. | virtual object [] ToArray()
virtual Array ToArray(Type type) |
TrimToSize
This method sets the capacity to the number of elements in the collection. | virtual void TrimToSize() |
IEnumerable members | GetEnumerator |
ICloneable members | Clone |
ICollection members | CopyTo, Count, IsSynchronized, and SyncRoot |
The following code uses some ArrayList methods and properties. It creates a new ArrayList. Elements then are added from command-line arguments. The command-line arguments should be integer values. Then the values of the elements in the cloned ArrayList are doubled. Afterward, the cloned ArrayList is enumerated and every element is displayed:
using System;
using System.Collections;
namespace Donis.CSharpBook {
public class Starter {
public static void Main(string [] argv) {
ArrayList al1 = new ArrayList();
foreach(string arg in argv) {
al1.Add(int.Parse(arg));
}
al1.Sort();
ArrayList al2 = (ArrayList)al1.Clone();
for (int count = 0; count < al2.Count; ++count) {
al2[count] = ((int)al2[count]) * 2;
}
foreach (int number in al2) {
Console.WriteLine(number);
}
}
}
}
The BitArray collection is a composite of bit values. Bit values are 1 and 0, where 1 is true and 0 is false. This collection provides an efficient means of storing and retrieving bit values.
Table 5-7 lists the methods and properties specific to a BitArray collection. The static members of the BitArray are thread-safe, whereas instance members are not.
Table 5-7. BitArray members
Member | Syntax |
---|
Constructor
The BitArray constructor is overloaded. These are some of the overloaded constructors. | BitArray(bool [] bits)
BitArray(int [] bits)
BitArray(int count,
bool default) |
And
This method performs a bitwise AND on the current instance and the BitArray parameter. The result is the returned BitArray. | BitArray And(BitArray value) |
Get
This method returns a specific bit in the BitArray collection. | bool Get(int index) |
IsReadOnly
This property returns true if the collection is read-only. Otherwise, the property returns false. | virtual bool IsReadOnly {
get; } |
Item
This property gets or sets the bit at the index. | virtual object this[int index] {
get; set; } |
Length
This property gets or sets the number of bits in the collection. | public int Length {
get; set; } |
Not
This method negates the bits of the BitArray collection. The result is the returned BitArray. | BitArray Not() |
Or
This method performs a bitwise OR on two BitArray collections, the current instance and the parameter. The result is in the returned BitArray. | BitArray Or(BitArray value) |
Set
This method sets a specific bit in the collection. | void Set(int index, bool value) |
SetAll
This method sets all the bits of the collection to true or false. | void SetAll(bool value) |
Xor
This method performs an exclusive OR on the current instance and the BitArray parameter. | BitArray Xor(
BitArray value) |
IEnumerable member | GetEnumerator |
ICloneable members | Clone |
ICollection members | CopyTo, Count, IsSynchronized, and SyncRoot |
The following code demonstrates the BitArray collection. The Employee class contains a BitArray collection that tracks employee enrollment in various programs, such as the health plan and the credit union. This is convenient because program enrollment is always either true or false. In the Employee class, properties are provided to set and get enrollment in various programs:
using System;
using System.Collections;
namespace Donis.CSharpBook {
public class Starter {
public static void Main() {
Employee ben = new Employee();
ben.InProfitSharing = false;
ben.InHealthPlan = false;
Employee valerie = new Employee();
valerie.InProfitSharing = false;
Participation("Ben", ben);
Participation("Valerie", valerie);
}
public static void Participation(string name, Employee person) {
Console.WriteLine(name + ":");
if (person.InProfitSharing) {
Console.WriteLine(" Participating in" +
" Profit Sharing");
}
if (person.InHealthPlan) {
Console.WriteLine(" Participating in" +
" Health Plan");
}
if (person.InCreditUnion) {
Console.WriteLine(" Participating in" +
" Credit Union");
}
}
}
public class Employee {
public Employee() {
eflags.SetAll(true);
}
private BitArray eflags = new BitArray(3);
public bool InProfitSharing {
set {
eflags.Set(0, value);
}
get {
return eflags.Get(0);
}
}
public bool InHealthPlan {
set {
eflags.Set(1, value);
}
get {
return eflags.Get(1);
}
}
public bool InCreditUnion {
set {
eflags.Set(2, value);
}
get {
return eflags.Get(2);
}
}
}
}
The Hashtable collection is a collection of key/value pairs. Entries in this collection are instances of the DictionaryEntry type. DictionaryEntry types have a Key and Value property to get and set keys and values.
In addition to the standard collection interfaces, the Hashtable collection implements the IDictionary, ISerializable, and IDeserializationCallback interfaces.
The entries are stored and retrieved in order based on the hash code contained in the key.
Table 5-8 lists the members of the Hashtable collection.
Table 5-8. Hashtable members
Member | Syntax |
---|
Constructor
The Hashtable constructor is overloaded. This is the syntax of some of the overloaded constructors. | Hashtable()
Hashtable(int capacity)
Hashtable(int capacity,
float loadFactor) |
Add
This method adds an element to the collection. | virtual void Add(object key,
object value) |
Clear
This method deletes all elements in the collection. | virtual void Clear() |
Contains
This method returns true if the key is found in the collection. If the key is not present, the method returns false. | virtual bool Contains(
object key) |
ContainsKey
This method returns true if the key is found in the collection. If the key is not present, it returns false. Identical to the Contains method. | virtual bool ContainsKey(
object key) |
ContainsValue
This method returns true if the value is found in the collection. If the value is not present, the method returns false. | virtual bool ContainsValue(
object value) |
GetEnumerator
This method returns an IDictionaryEnumerator object, which can be used to enumerate the elements of the hashtable. | virtual IDictionaryEnumerator
GetEnumerator() |
GetHash
This method returns the hash code for the specified key. | virtual int GetHash(
object key) |
GetObjectData
This method serializes the hashtable collection. | virtual void GetObjectData(
SerializationInfo info,
StreamingContext context) |
IsFixedSize
This property returns true if the collection is of fixed size. Otherwise, it returns false. | virtual bool IsFixedSize {
get; } |
IsReadOnly
This property returns true if the collection is read-only. Otherwise, it returns false. | virtual bool IsReadOnly {
get; } |
IsSynchronized
This property returns true if the collection is synchronized. | virtual bool IsSynchronized {
get; } |
Item
This property gets or sets a value pertaining to a key. | virtual object this[object key] {
get; set; } |
KeyEquals
This method compares a key to a value. If they are equal, true is returned; if not, false is returned. This method is used primarily to compare two keys. | virtual bool KeyEquals(
object item,
object key) |
Keys
This method returns a collection that contains the keys of the hashtable. | virtual ICollection Keys {
get; } |
OnDeserialization
This method is called when deserialization is completed. | virtual void OnDeserialization(
object sender) |
Remove
This method removes an element of the specified key from the collection. | virtual void Remove(
object key) |
Synchronized
This method returns a thread-safe wrapper of the collection. | static Hashtable Synchronized(
Hashtable sourceTable) |
Values
This property returns a collection that has the values of the hashtable. | virtual ICollection Values {
get; } |
IEnumerable members | GetEnumerator |
ICloneable members | Clone |
ICollection members | CopyTo, Count, IsSynchronized, and SyncRoot |
Hashtable.GetEnumerator implements IDictionary.GetEnumerator, which returns an IDictionaryEnumerator. IDictionaryEnumerator implements the IEnumerator interface, while also adding three properties: Entry, Key, and Value.
The following code extends the previous sample code for the BitArray collection. The program creates a Hashtable, where each element is an employee. The key is the employee ID, and the value is an instance of an Employee type:
using System;
using System.Collections;
namespace Donis.CSharpBook {
public class Starter {
public static void Main() {
Hashtable employees = new Hashtable();
employees.Add("A100", new Employee(
"Ben", true, false, true));
employees.Add("V100", new Employee(
"Valerie", false, false, true));
Participation((Employee) employees["A100"]);
Participation((Employee) employees["V100"]);
}
public static void Participation(Employee person) {
Console.WriteLine(person.Name + ":");
if (person.InProfitSharing) {
Console.WriteLine(" Participating in" +
" Profit Sharing");
}
if (person.InHealthPlan) {
Console.WriteLine(" Participating in" +
" Health Plan");
}
if (person.InCreditUnion) {
Console.WriteLine(" Participating in" +
" Credit Union");
}
}
}
public class Employee {
public Employee(string emplName) {
propName = emplName;
eflags.SetAll(true);
}
public Employee(string emplName,
bool profitSharing,
bool healthPlan,
bool creditUnion) {
propName = emplName;
InProfitSharing = profitSharing;
InHealthPlan = healthPlan;
InCreditUnion = creditUnion;
}
private BitArray eflags = new BitArray(3);
public bool InProfitSharing {
set {
eflags.Set(0, value);
}
get {
return eflags.Get(0);
}
}
public bool InHealthPlan {
set {
eflags.Set(1, value);
}
get {
return eflags.Get(1);
}
}
public bool InCreditUnion {
set {
eflags.Set(2, value);
}
get {
return eflags.Get(2);
}
}
private string propName;
public string Name {
get {
return propName;
}
}
}
}
This is sample code that shows the use of an IDictionaryEnumerator enumerator:
using System;
using System.Collections;
namespace Donis.CSharpBook {
public class Starter {
public static void Main() {
Hashtable zHash = new Hashtable();
zHash.Add("one", 1);
zHash.Add("two", 2);
zHash.Add("three", 3);
zHash.Add("four", 4);
IDictionaryEnumerator e =
zHash.GetEnumerator();
while (e.MoveNext()) {
Console.WriteLine(
"{0} {1}",
e.Key, e.Value);
}
}
}
}
A Queue collection abstracts a FIFO data structure. Queue collections are ideal for implementing messaging components.
Table 5-9 lists the members of the Queue collection.
Table 5-9. Queue members
Member | Syntax |
---|
Constructor
The Queue constructor is overloaded. This is the syntax of the overloaded constructors. | public Queue()
public Queue(
ICollection sourceCollection)
public Queue(int capacity)
public Queue(int capacity,
float factor) |
Clear
This method removes all the elements of the collection. | virtual void Clear() |
Contains
This method returns true if the specified value is found in the collection. If the value is not found, the method returns false. | virtual bool Contains(object value) |
Dequeue
This method removes and returns the first element on the queue. | virtual object Dequeue() |
Enqueue
This method adds an element to the queue. | virtual void Enqueue(
object element) |
Peek
This method returns the first element of the queue without removing it. | virtual object Peek() |
Synchronized
This method returns a thread-safe wrapper for a queue object. | static Queue Synchronized(
Queue sourceQueue) |
ToArray
This method creates a new array from the elements of the queue. | virtual object[] ToArray() |
TrimToSize
This method sets the capacity to the number of elements in the collection. | virtual void TrimToSize() |
IEnumerable members | GetEnumerator |
ICloneable members | Clone |
ICollection members | CopyTo, Count, IsSynchronized, and SyncRoot |
This is sample code of the Queue collection. Customers are added to the queue and then displayed:
using System;
using System.Collections;
namespace Donis.CSharpBook {
public class Starter {
public static void Main() {
Queue waiting = new Queue();
waiting.Enqueue(new Customer("Bob"));
waiting.Enqueue(new Customer("Ted"));
waiting.Enqueue(new Customer("Kim"));
waiting.Enqueue(new Customer("Sam"));
while (waiting.Count != 0) {
Customer cust =
(Customer) waiting.Dequeue();
Console.WriteLine(cust.Name);
}
}
public class Customer {
public Customer(string cName) {
propName = cName;
}
private string propName;
public string Name {
get {
return propName;
}
}
}
}
}
The SortedList collection is a combination of key/value entries and an ArrayList collection, where the collection is sorted by the key. Elements of the collection are accessible either through the key or through an index.
Table 5-10 includes the members of the SortedList collection.
Table 5-10. SortedList members
Member | Syntax |
---|
Constructor
The SortedList constructor is overloaded. These are some of the overloaded constructors. | SortedList()
SortedList(IComparer comparer)
SortedList(
IDictionary sourceCollection) |
Add
This method adds an element to the collection. | virtual void Add(object key,
object value) |
Capacity
This property gets or sets the capacity of the collection. | virtual int Capacity {
get; set; } |
Clear
This method removes all the elements of the collection. | virtual void Clear() |
Contains
This method returns true if the specified value is found in the collection. If the value is not found, the method returns false. | virtual bool Contains(object value) |
ContainsKey
This method returns true if the key is found in the collection. If the key is not present, it returns false. Identical to the Contains method. | virtual bool ContainsKey(
object key) |
ContainsValue
This method returns true if the value is found in the collection. If the value is not present, it returns false. | virtual bool ContainsValue(
object value) |
GetByIndex
This method returns the value at the specified index. | virtual object GetByIndex(
int index) |
GetKey
This method returns the key at the specified index. | virtual object GetKey(
int index) |
GetKeyList
This method returns all the keys of the collection in a list. | virtual IList GetKeyList() |
GetValueList
This method returns all the values of the SortedList in a new list. | virtual IList GetValueList() |
IndexOfKey
This method returns the index of a key found in the collection. If not found, -1 is returned. | virtual int IndexOfKey(
object key) |
IndexOfValue
This method returns the index to the first instance of this value in the collection. | virtual int IndexOfValue(
object value) |
IsFixedSize
This property returns true if the collection is of fixed size. Otherwise, it returns false. | virtual bool IsFixedSize {
get; } |
IsReadOnly
This property returns true if the collection is read-only. Otherwise, it returns false. | virtual bool IsReadOnly {
get; } |
Item
This property gets or sets the value of this key. | virtual object this[object key] {
get; set; } |
Keys
This property returns the keys of the SortedList in a collection. | public virtual ICollection Keys {
get; } |
Remove
This method removes the element identified by the key from the collection. | virtual void Remove(
object key) |
RemoveAt
This method removes the element at the specified index. | virtual void RemoveAt(
int index) |
SetByIndex
This method sets the value of the element at the specified index. | virtual void SetByIndex(
int index, object value) |
Synchronized
This method returns a thread-safe wrapper for a SortedList object. | static SortedList Synchronized(
SortedList sourceList) |
TrimToSize
This method trims the capacity to the actual number of elements in the collection. | virtual void TrimToSize() |
Values
This property returns the values in a collection. | virtual ICollection Values {
get; } |
IEnumerable members | GetEnumerator |
ICloneable members | Clone |
ICollection members | CopyTo, Count, IsSynchronized, and SyncRoot |
The following program is an application that tracks auto repair tickets. Each ticket, which is an instance of the AutoRepairTicket class, is added to a sorted list. The key is the customer name. The value is the actual ticket. After populating the SortedList type, the CustomerReport method lists the open tickets:
using System;
using System.Collections;
namespace Donis.CSharpBook {
public class Starter {
public static void Main() {
SortedList tickets = new SortedList();
AutoRepairTicket ticket = NewTicket("Ben");
tickets.Add(ticket.Name, ticket);
ticket = NewTicket("Donis");
tickets.Add(ticket.Name, ticket);
ticket = NewTicket("Adam");
tickets.Add(ticket.Name, ticket);
CustomerReport(tickets);
}
public static AutoRepairTicket NewTicket(
string customerName) {
return new AutoRepairTicket(customerName,
DateTime.Now);
}
public static void CustomerReport(SortedList list) {
foreach (DictionaryEntry entry in list) {
int nextTag = ((AutoRepairTicket) entry.Value).Tag;
string nextTime = ((AutoRepairTicket)
entry.Value).Time.ToShortTimeString();
Console.WriteLine("Customer: {0} Ticket: {1} Time: {2}",
entry.Key, nextTag, nextTime);
}
}
}
public class AutoRepairTicket{
public AutoRepairTicket(string customerName,
DateTime ticketTime) {
propName = customerName;
propTime = ticketTime;
propTag = ++count;
}
private string propName;
public string Name {
get {
return propName;
}
}
private DateTime propTime;
public DateTime Time {
get {
return propTime;
}
}
private int propTag;
public int Tag {
get {
return propTag;
}
}
private static int count = 1000;
}
}
A Stack collection abstracts a LIFO data structure.
Table 5-11 lists the members of the Stack collection.
Table 5-11. Stack members
Member | Syntax |
---|
Clear
This method removes all the elements of the collection. | virtual void Clear() |
Contains
This method returns true if the specified value is found in the collection. If the value is not found, the method returns false. | virtual bool Contains(object value) |
Peek
This method previews the most recent element on the stack. The element is returned without removing it from the stack. | virtual object Peek() |
Pop
This method returns and removes the top element of the stack. | virtual object Pop() |
Push
This method pushes an element onto the stack. | virtual void Push(object obj) |
Synchronized
This method returns a thread-safe wrapper for the Stack collection. | static Stack Synchronized(
Stack sourceStack) |
ToArray
This method returns the elements of the Stack collection as a regular array. | virtual object[] ToArray() |
The following code adds numbers to a Stack collection. The values of the elements in the collection are removed from the stack and then displayed to the Console window:
using System;
using System.Collections;
namespace Donis.CSharpBook {
public class Starter {
public static void Main() {
Stack numbers = new Stack(
new int[] {1,2,3,4,5,6});
int total = numbers.Count;
for (int count = 0; count < total; ++count) {
Console.WriteLine(numbers.Pop());
}
}
}
}
In addition to the common collections that most developers use, the .NET FCL offers specialized collections. These collections are found in the System.Collections.Specialized namespace. Although these collections are used infrequently, they are valuable in certain circumstances.
Table 5-12 lists the specialized collections.
Table 5-12. Specialized collections in the .NET FCL
Member | Description |
---|
BitVector32 | This is an array of 32 bits. It is similar to a BitArray, but it is limited to 32 bits. Because of this array’s refined use, BitVector32 structures are more efficient than a BitArray collection. |
HybridDictionary | This collection is a combination of a ListDictionary and a Hashtable. It operates as a ListDictionary when it contains a small number of elements. For optimum performance, the collection switches to a Hashtable as the number of elements increases. |
NameValueCollection | This is a collection of keys and values, in which both the keys and values are strings. The collection is accessible via an index or key. A key can refer to multiple values. |
OrderedDictionary | This is a collection of key and value pairs, where each entry is accessible by either the key or the value. |
StringCollection | This is a collection of strings. |
StringDictionary | This is a combination of the Hashtable and StringCollection collections, in which both the keys and values are strings. |