Chapter 5: Arrays and Collections

Chapter 5: Arrays and Collections


An array is a collection of related instances, either value or reference types. Arrays possess an immutable structure, in which the number of dimensions and size of the array are fixed at instantiation. C# supports single-dimensional, multidimensional, and jagged arrays. Single-dimensional arrays, sometimes called vectors, consist of a single row. Multidimensional arrays are rectangular and consist of rows and columns. A jagged array also consists of rows and columns, but is irregularly shaped.

Arrays are represented in most programming languages. Most developers have some familiarity with the concept of arrays. Arrays are employed in a variety of ways. A personnel program would contain an array of employees. Graphic programs might have one array for each type of geometric object, such as ellipses, rectangles, or triangles. An accounting and scheduling application for automobile repair likely would have an array of automobile repair tickets. The Space Shuttle program would have an array of astronauts.

Arrays are intrinsic to the language. Other collections, such as Stack, Queue, and Hashtable, are not native to the language. As such, ease of use is one of the benefits of arrays. Another benefit is familiarity. Arrays are available and functionally similar in almost every programming language. Few developers have not worked with arrays.

An array is a container, which is an abstraction of a data structure. As a container, an array holds data items called elements. Elements of an array are always related, such as an array of apples or an array of oranges. An array might consist of SalariedEmployee, HourlyEmployee, and CommissionedEmployee instances. However, an array of apples and employees is probably invalid because those objects are probably unrelated. In addition, an array is a data structure that is a composite of elements that reside in contiguous memory.

Arrays are reference types, and the memory for the array is allocated on the managed heap. Even an array of value types is allocated on the managed heap and not on the stack. An array of 30 integer values would have the same number of 32-bit slots allocated in contiguous memory for the array elements. With arrays of reference types, the objects are not stored in contiguous memory; the references are stored in contiguous memory. However, the objects themselves are stored in noncontiguous memory, which is pointed to by the reference. Figure 5-1 shows the difference in memory allocation between arrays of reference versus value types.

Image from book
Figure 5-1: Array of reference types versus value types

Elements are relative to the beginning of the array and are identified with indexes, which are either integer or long types. Indexes are also commonly called indices or subscripts, and placed inside the indexing operator ([ ]). Arrays are zero-based where the index is actually an offset. Array indexes are offsets from the beginning of the array to a particular element. Therefore, the first element is at the start of the array, which is an offset of zero. For an array of five elements, a proper index is from zero to four. Therefore, the last element of the array is at index n -- 1. This is a common cause of fencepost errors. Fencepost errors occur when referring to array elements with indexes outside the bounds of an array. If an array has five elements, accessing element six is a fencepost error.

As mentioned, arrays are immutable. This means that an array is statically sized, and the dimensions cannot be changed at run time. The System.Array.Resize method, which is a generic method, seemingly resizes an array. However, appearances can be deceiving. Array.Resize creates an entirely new array that is the new size. The new array is initialized with the elements of the source array. Afterward, the original array is discarded.

Single-dimensional arrays are indigenous to the run time. There are specific MSIL instructions for vectors, including newarr, ldelem, ldlen, and stelem. There are no built-in instructions for multidimensional arrays. This direct manipulation of single-dimensional arrays makes them more efficient. In addition, some of the members of the System.Array type, which is the underlying type for all arrays, cannot be applied to multidimensional arrays. Conversely, all the methods and properties of the System.Array type are applicable to single-dimensional arrays.

The System.Array type is the underpinning of all arrays. It is an abstraction of an array. Instances of arrays are instances of the System.Array type. Thus, arrays are implicitly reference types. Arrays can access many of the instance methods and properties of the System.Array type. System.Array is a combination of original methods and the implementation of a series of interfaces. Table 5-1 lists the interfaces that System.Array implements.

Table 5-1: Interfaces Implemented at System.Array




This interface defines a method to clone an instance of an array.


This interface defines methods to count the number of elements of an array and for thread synchronization.


This interface defines a method that enumerates the elements of a collection.


The interface defines methods to access an index-based collection. Some members of this interface are not publicly implemented.

Create arrays as local variables or fields. Use arrays also as method parameters and return types. The rationale of using an array as a local variable, field, method parameter, or return type is the same as any type. Arrays are passable into or out of a method as a parameter. The semantics of an array parameter are the same as any parameter. Because an array is a reference type, it is passed by reference. Therefore, the content of the array can be changed in the called method. Parameter modifiers, such as the ref modifier, are assignable to array parameters.