Contents
1. Introduction
Just like C++, C# has different types of collections you can use to manage data. In this knol, we’ll discuss arrays and the containers from the System.Collections namespace.
Note that the containers of the System.Collections namespace are not recommended. The reason is that they cause a lot of boxing and unboxing. You should use generic collections from the System.Collections.Generic namespace (like List<T>), which I will explain in part 2.
2. Array
2.1 General
Unlike C++, where an array is just a pointer to the first item in that array, in C# an array is an object of type System.Array. This means an array is a real class with properties and methods, which makes handling arrays a lot easier in C# than C++. You also can’t go beyond the memory allocation of the array. If you try to access an element outside of the bounds of the array, you will get an IndexOutOfRange exception.
Just like C++, an array is a sequence of elements, and all elements must be of the same type. The elements also live in a continuous block of memory.
Declaring an array is similar to the way you do it in C++, except the fact that you put the square brackets after the type, not the variable name.
int[] arr = new int [5];
The code above creates an array of integers, that reserves memory for 5 elements. You always have to call new in order to create a new array. The size of the array can be determined at runtime. The code below is completely valid (assuming you enter the correct input in the console).
int[] arr = new int[int.Parse(Console.ReadLine())];
When you create an array instance, all elements are initialized to their default value (depending on their type). You can also initialize the elements to a specific value, by specifying them between curly braces.
int[] arr = new int [5] {1,2,3,4,5};
Or even shorter:
int[] arr = {1,2,3,4,5};
2.2 Iterating an array
An array has a property Length, which tells you how many items the array contains. This property makes iterating an array very easy.
for (int i = 0; i < arr.Length; ++i)
Console.WriteLine(i.ToString());
You can also use the foreach statement to iterate through an array, and all collections as a matter of a fact. This is because they implement the IEnumerable interface. In future knols, you will learn more of IEnumerable, but for now it’s enough if you know that implementing the interface enables you to loop through a collection using a foreach statement.
foreach(int i in arr)
Console.WriteLine(i.ToString());
Foreach always iterates though all the items of the collection, from the first to the last element. If you want to iterate backwards, or skip certain items, you must use the ‘for’ statement.
2.3 Copying arrays
2.3.1 Shallow and deep copy
First of all, it’s necessary that you know the difference between shallow and deep copy. If the elements that your array contains are reference types, a shallow copy will copy the references, but not the objects to which they point. So after the copy operation both the original and the copy point to the same objects. A deep copy will clone the objects themselves, so the original and the copy don’t point to the same objects.
All copy methods you will see below perform shallow copying. If you want to create a deep copy, you’ll need to write the code yourself.
2.3.2 Copy
The System.Array class has a static method Copy. You can use this method to create a shallow copy of an array. It takes the original array, the destination array and the length as arguments.
int[] original = new int[10] { 1, 2, 3, 4, 5 };
int[] copy = new int[5];
Array.Copy(original, copy, 5);
2.3.3 CopyTo
Another way to copy an array is to use the CopyTo method. It takes to destination array and a starting index as arguments.
int[] original = new int[5] { 1, 2, 3, 4, 5 };
int[] copy = new int[5];
original.CopyTo(copy, 0);
2.3.4 Clone
An array also has a Clone method, which creates a shallow copy of the array and returns the copy. The Clone method creates the object for you; you do have to cast the return value to the appropriate type.
int[] original = new int[5] { 1, 2, 3, 4, 5 };
int[] copy = (int[]) original.Clone();
3. Collections
Unlike C++, it is safe to use arrays in C#. However they do have certain limitations. In the System.Collections namespace, several collections that will make your life easier are provided. All collections implement the IEnumerable interface, so you can make use of the foreach statement. Most collections from the System.Collection namespace use object as type for their elements. So object[] instead of int[] for example. The System.Collections.Generics namespace offers a solution for that. This will be discussed in the 2ndcollections knoll.
3.1 ArrayList
An arraylist is a collection that doesn’t have a fixed number of elements like an array does. It’s also very useful when you want to add, insert and remove a lot of elements at runtime.
When you use an array and you want to resize it, you have to create a new one, copy the elements, update references, … Removing items from the array means you’ll have to move all trailing elements, … The arraylist does all this for you. You use an ArrayList as is shown below:
// Create a new arraylist
ArrayList myAL = new ArrayList();
myAL.Add(“Hello”);
myAL.Add(“!”);
// Insert World between Hello and !
myAL.Insert(1, “World”);
// Add two items to the end of the arraylist
myAL.Add(“test”);
myAL.Add(“test2″);
// Remove the items that have “test” as value
myAL.Remove(“test”);
// Remove the item at index 3
myAL.RemoveAt(3);
// Displays the properties and values of the ArrayList.
Console.WriteLine(“myAL”);
Console.WriteLine(“ Count: {0}”, myAL.Count);
Console.WriteLine(“ Capacity: {0}”, myAL.Capacity);
Console.Write(“ Values:”);
// Write all objects to console. Note the object keyword!
foreach (Object obj in myAL)
Console.Write(“ {0}”, obj);
Console.WriteLine();
3.2 BitArray
The BitArray container is a compact array of bit values that represent booleans. 1 indicates that the bit is on (true), 0 that the bit is off (false).
3.3 Hashtable
An arraylist for example, makes it easy to map an integer (index) to a certain value. But sometimes we want the key (the index) to be something different than an integer. A hashtable has two arrays internally, one for the keys, and one for the objects. A hashtable is very similar to the C++ map.
There are some things one should be aware of however:
-
A hashtable cannot contain duplicate keys.
-
A hashtable can contain duplicate values.
-
When using the foreach statement on a hashtable, you get back objects of type DictionaryEntry.
Hashtable openWith = new Hashtable();
// Add some elements to the hash table. There are no
// duplicate keys, but some of the values are duplicates.
openWith.Add(“txt”, “notepad.exe”);
openWith.Add(“bmp”, “paint.exe”);
openWith.Add(“dib”, “paint.exe”);
openWith.Add(“rtf”, “wordpad.exe”);
// The Add method throws an exception if the new key is
// already in the hash table.
try
{
openWith.Add(“txt”, “winword.exe”);
}
catch
{
Console.WriteLine(“An element with Key = \”txt\” already exists.”);
}
foreach (DictionaryEntry entry in openWith)
Console.Write(“ {0}, {1}”, entry.Key, entry.Value);
Console.WriteLine();
3.4 Queue
The queue in C# is very similar to the C++ queue. It’s a collection that implements the first-in, first-out (FIFO) principle. Items that are queued are inserted at the back, and removed from the front.
Usage is very straightforward:
Queue myQ = new Queue();
myQ.Enqueue(“Hello”);
myQ.Enqueue(“World”);
myQ.Enqueue(“!”);
// Displays the properties and values of the Queue.
Console.WriteLine(“myQ”);
Console.WriteLine(“\tCount: {0}”, myQ.Count);
Console.Write(“\tValues:”);
// Write all items to the console
foreach (Object obj in myQ)
Console.Write(“ {0}”, obj);
// dequeue the first item (Hello)
string hello = (string) myQ.Dequeue();
Console.WriteLine();
3.5 SortedList
A sorted list is very similar to a hashtable, except that the values are sorted by key. The usage and restrictions of the sorted list are similar to the hashtable.
// The items will be sorted by key
SortedList mySL = new SortedList();
mySL.Add(“First”, “Hello”);
mySL.Add(“Third”, “!”);
mySL.Add(“Second”, “World”);
// Displays the properties and values of the SortedList.
Console.WriteLine(“mySL”);
Console.WriteLine(“ Count: {0}”, mySL.Count);
Console.WriteLine(“ Capacity: {0}”, mySL.Capacity);
Console.WriteLine(“ Values:”);
foreach (DictionaryEntry entry in mySL)
Console.Write(“ {0}, {1}”, entry.Key, entry.Value);
Console.WriteLine();
3.6 Stack
The stack in C# is also very similar to the C++ stack. It’s a collection that implements the last-in, first-out (LIFO) principle. An element is added (push) to the top of the stack, and removed (pop) from the top as well.
Stack myStack = new Stack();
myStack.Push(“Hello”);
myStack.Push(“World”);
myStack.Push(“!”);
// Displays the properties and values of the Stack.
Console.WriteLine(“myStack”);
Console.WriteLine(“\tCount: {0}”, myStack.Count);
Console.Write(“\tValues:”);
foreach (Object obj in myStack)
Console.Write(“ {0}”, obj);
// Pop the first item (!)
string exlamationmark = (string)myStack.Pop();
Console.WriteLine();