Array Class
Declaring an array with brackets is a C#
notation of using the Array class. Using
the C# syntax behind the scenes creates a new class that derives
from the abstract base class Array. It
is possible, in this way, to use methods and properties that are
defined with the Array class with every
C# array. For example, you’ve already used the Length property or iterated through the array by
using the foreach statement. By doing
this, you are using the GetEnumerator()
method of the Array class.
Properties
The Array class
contains the following properties that you can use with every array
instance. There are some more properties available that will be
discussed later in this chapter.
Creating Arrays
The Array class is
abstract, so you cannot create an array by using a constructor.
However, instead of using the C# syntax to create array instances,
it is also possible to create arrays by using the static
CreateInstance() method. This is
extremely useful if you don’t know the type of the elements in
advance, as the type can be passed to the CreateInstance() method as a Type object.
The following example shows how to create an array
of type int with a size of 5. The first
argument of the CreateInstance() method
requires the type of the elements, and the second argument defines
the size. You can set values with the SetValue() method, and read values with the
GetValue() method.
You can also cast the created array to an array
declared as int[]:
The CreateInstance()
method has many overloads to create multidimensional arrays and
also to create arrays that are not 0-based. The following example
creates a 2-dimensional array with 2 × 3 elements. The first
dimension is 1-based; the second dimension 10-based.
Setting the elements of the array, the SetValue() method accepts indices for every
dimension:
Although the array is not 0-based you can assign it
to a variable with the normal C# notation. You just have to pay
attention to not crossing the boundaries.
Copying Arrays
Because arrays are reference types, assigning
an array variable to another one you just have two variables
referencing the same array. For copying arrays, the array
implements the interface ICloneable. The
Clone() method that is defined with this
interface creates a shallow copy of the array.
If the elements of the array are value types, all
values are copied, as you can see in Figure 5-5.
If the array contains reference types, the elements
are not copied, just the references. Figure 5-6 shows the variables beatles and beatlesClone
where beatlesClone is created by calling
the Clone() method from beatles. The Person
objects that are referenced are the same with beatles and beatlesClone.If you change a property of an element
of beatlesClone, you change the same
object of beatles.
Instead of using the Clone() method, you can also use the Array.Copy() method that creates a shallow copy as
well. But there’s one important difference with Clone and Copy:
Clone creates a new array, with Copy you have to pass an existing
array with the same rank and enough elements.
|
|
Tip |
If you need a deep copy of an array
containing reference types, you have to iterate the array and
create new objects.
|
Sorting
The Array class
implements a bubble-sort for sorting the elements in the array. The
Sort() method requires the interface
IComparable to be implemented by the
elements in the array. Simple types such as System.String and System.Int32 implement IComparable, so you can sort elements containing
these types.
With the sample program, the array name contains
elements of type string, and this array can be sorted.
The output of the application shows the sorted
result of the array:
If you are using custom classes with the array, you
must implement the interface IComparable. This interface defines just one method
CompareTo() that must return 0 if the
objects to compare are equal, a value smaller than 0 if the
instance should go before the object from the parameter, and a
value larger than 0 if the instance should go after the object from
the parameter.
Change the Person class
to implement the interface IComparable.
The comparison is done on the value of the lastname. As the lastname
is of type string, and the String class already implements the ICompareable interface, with the implementation you
can rely on the CompareTo() method of
the String class:
Now it is possible to sort an array of Person objects by the last name:
Using the sort of the Person class, the output returns the names sorted by
the last name:
If the Person object
should be sorted differently, or if you don’t have the option to
change the class that is used as an element in the array, you can
implement the interface IComparer. This
interface defines the method Compare().
The interface IComparable must be
implemented by the class that should be compared. The IComparer interface is independent of the class to
compare. That’s why the Compare()
method defines two arguments
that should be compared. The return value is similar to the
CompareTo() method of the IComparable interface.
The class PersonComparer
implements the IComparer interface to
sort Person objects either by
firstname or by lastname. The enumeration PersonCompareType defines the different sorting
options that are available with the PersonComparer: Firstname
and Lastname. How the compare should
happen is defined with the constructor of the class PersonComparer where a PersonCompareType value is set. The Compare() method is implemented with a switch statement to compare either by lastname or by firstname.
Now you can pass a PersonComparer object to the second argument of the
Array.Sort() method. Here the persons
are sorted by first name:
The persons array is now sorted by the first
name:
|
|
Tip |
The Array class
also offers Sort methods that require a
delegate as an argument. In Chapter 7, “Delegates
and Events,” you can read all the information on how to use
delegates.
|
|