.Net application development specialists
asp.net, c#, vb.net, html, javascript, jquery, html, xhtml, css, oop, design patterns, sql server, mvc and much more
contact: admin@paxium.co.uk

Paxium is the company owned by myself, Dave Amour and used for providing IT contract development services including


  • Application development - Desktop, Web, Services - with Classic ASP, Asp.net WebForms, Asp.net MVC, Asp.net Core
  • Html, Css, JavaScript, jQuery, React, C#, SQL Server, Ado.net, Entity Framework, NHibernate, TDD, WebApi, GIT, IIS
  • Database schema design, implementation & ETL activities
  • Website design and hosting including email hosting
  • Training - typically one to one sessions
  • Reverse Engineering and documentation of undocumented systems
  • Code Reviews
  • Performance Tuning
  • Located in Cannock, Staffordshire
Rugeley Chess Club Buying Butler Cuckooland Katmaid Pet Sitting Services Roland Garros 60 60 Golf cement Technical Conformity Goofy MaggieBears Vacc Track Find Your Smart Phone eBate Taylors Poultry Services Lafarge Rebates System Codemasters Grid Game eBate DOFF

Collection Classes in .net

There are many classes in .net for working with Collections.

This article will look at the most common ones and attempt to give an overview, pros and cons and code examples to help you become more familliar with what options are at your disposal.  This will hopefully leave you in a better position to make a more informed choice when deciding which collection class best suits your particular needs.

The classes which we will look at are as follows:

Array
ArrayList
List
HashTable
Dictionary
Stack
Queue
LinkedList
StringCollection
SortedList
StringDictionary
SortedDictionary
HybridDictionary
ListDictionary
NameValueCollection

Array

This can be found at System.Arrray

C# arrays are zero indexed - that is the array indexes start at zero. Arrays in C# work similarly to how arrays work in most other popular languages.  C# supports single-dimensional arrays, multidimensional arrays (rectangular arrays), and array-of-arrays (jagged arrays).

You should be aware that arrays, when treated as a whole - ie an instance of the System.Array class, are treated as reference types.  If however you work with individual elements in an array then they will be the same type  as what the individual elements is.  So if you have an array of ints and you deal with one element on it's own then that will be treated as a value type.  If on the other hand you deal with say an array of StringBuilders then they will individually be treated as reference types.

We can check this by creating and running the following 2 programs.  They both create an array and then output the array contents to screen.  They then push the array through a method and make some changes.  It then outputs the array contents to screen so we can see that the array was passed by reference.  The code then pushes just one element of the array through a method.  The method changes the value again and then then outputs the array contents to screen.  Here we can see that an array of ints passes by value when we pass an individual array element whereas an array of StringBuulders (reference types) passes by reference when we pass an individual element.

Array of Ints

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
 
namespace Collections
{
    class Program
    {
        static void Main(string[] args)
        {
            int[] myInts = new int[] { 1, 2, 3, 4 };
 
            Console.WriteLine("Here is the initial array of ints");
 
            foreach (int i in myInts)
            {
                Console.WriteLine(i);
            }
 
            Console.WriteLine();
 
            ChangeArray(myInts);
 
            Console.WriteLine("Here is the array of ints after ChangeArray(myInts)");
 
            foreach (int i in myInts)
            {
                Console.WriteLine(i);
            }
 
            Console.WriteLine();
 
            Console.WriteLine("Here is the array of ints after ChangeArrayMember(myInts[0])");
 
            ChangeArrayMember(myInts[0]);
 
            foreach (int i in myInts)
            {
                Console.WriteLine(i);
            }
 
            Console.Read();
        }
 
        static void ChangeArray(int[] array)
        {
            array[0] = 1111;
            array[1] = 2222;
            array[2] = 3333;
            array[3] = 4444;
        }
 
        static void ChangeArrayMember(int i)
        {
            i = 88;
        }
    }
}
 

Program Output

Array Of StringBuilders

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
 
namespace Collections
{
    class StringBuildersArray
    {
        static void Main()
        {
            StringBuilder[] myStringBuilders = new StringBuilder[5];
 
            myStringBuilders[0] = new StringBuilder("AAAAA");
            myStringBuilders[1] = new StringBuilder("BBBBB");
            myStringBuilders[2] = new StringBuilder("CCCCC");
            myStringBuilders[3] = new StringBuilder("DDDDD");
            myStringBuilders[4] = new StringBuilder("EEEEE");
 
            Console.WriteLine("Initial Array");
           
            foreach (StringBuilder sb in myStringBuilders)
            {
                Console.WriteLine(sb.ToString());
            }
 
            Console.WriteLine();
 
            Console.WriteLine("Array after ChangeArray(StringBuilder[] myStringBuilders)");
 
            ChangeArray(myStringBuilders);
 
            foreach (StringBuilder sb in myStringBuilders)
            {
                Console.WriteLine(sb.ToString());
            }
 
            Console.WriteLine();
 
            Console.WriteLine("Array after ChangeArrayElement(StringBuilder[0]");
 
            ChangeArrayElement(myStringBuilders[0]);
 
            foreach (StringBuilder sb in myStringBuilders)
            {
                Console.WriteLine(sb.ToString());
            }
 
            Console.Read();
        }
 
        static void ChangeArray(StringBuilder[] myStringBuilders)
        {
            myStringBuilders[0].Append("ZZZZZ");
        }
 
        static void ChangeArrayElement(StringBuilder myStringBuilder)
        {
            myStringBuilder.Append("YYYYY");
        }
    }
}
 


Multidimensional Arrays

So far we have just looked at single dimensional arrays.  It is possible though to have arrays with more than 1 dimension.  To illustrate this consider the following program. 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
 
namespace Collections
{
    class ArrayTest3
    {
        static void Main()
        {
            int[,] myInts2 = new int[2, 4];
 
            for (int i = 0; i < myInts2.GetLength(0); i++)
            {
                for (int j = 0; j < myInts2.GetLength(1); j++)
                {
                    Console.WriteLine("myInts2[{0} {1}]", i, j);
                }
            }
 
            Console.Read();
        }
    }
}
 


The output from this program when executed looks like this:

So we can see that it is a 2 dimensional array with the first dimension having 2 entries and the second dimension having 4 entries which gives us 8 elements in total.   Multidimensional arrays are very useful for modelling real world problems.  For example we could have an 8 x 8 array to model a chess board if we were going to be writing a chess playing program.  We can also have a 3 dimensional array which would be [3, 3, 3] for example giving us 27 elements which might be a good way to write a program we might write to solve a Rubiks cube.

And so we can have pretty much whatever size dimension we need to solve our problem.   For example the code below has a 5 dimensional array.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
 
namespace Collections
{
    class ArrayTest3
    {
        static void Main()
        {
            int[,,,,] myInts = new int[2, 2, 2, 2, 2];
 
            for (int i = 0; i < myInts.GetLength(0); i++)
            {
                for (int j = 0; j < myInts.GetLength(1); j++)
                {
                    for (int k = 0; k < myInts.GetLength(2); k++)
                    {
                        for (int l = 0; l < myInts.GetLength(3); l++)
                        {
                            for (int m = 0; m < myInts.GetLength(4); m++)
                            {
                                Console.WriteLine("myInts[{0}, {1}, {2}, {3}, {4}] = {5}", i, j, k, l, m, myInts[i, j, k, l, m]);
                            }
                        }
                    }                   
                }
            }
 
            Console.Read();
        }
    }
}
 


Because the array is actually an instance of  System.Array then out of the box we will get lot sof built in functionality.  Sorting for example is a built in method.  This is actually a static method of the Array class though and takes an array as a parameter.  Personally I would have thought it more natural to have this as an instance method.  There is also a Reverse method which is a static method also.

These can be seen in action in the following code.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
 
namespace Collections
{
    class Sorting
    {
        static void Main()
        {
            int[] myInts = new int[] {3, 44, 5, 1, 2, 98, 43, 2332, 3, 22 };
 
            Console.WriteLine("Initial Array");
           
            foreach (int i in myInts)
            {
                Console.WriteLine(i);
            }
 
            Array.Sort(myInts);
 
            Console.WriteLine();
 
            Console.WriteLine("Sorted Array");
 
            foreach (int i in myInts)
            {
                Console.WriteLine(i);
            }
 
            Array.Reverse(myInts);
 
            Console.WriteLine();
 
            Console.WriteLine("Sorted Array in Reverse");
 
            foreach (int i in myInts)
            {
                Console.WriteLine(i);
            }
 
            Console.Read();
        }
    }
}
 


The output from this code looks like this:

 

Other methods of interest are Clone and CopyTo.  Both of these are instance methods rather than static methods.

The Clone method creates a copy of the array.  This method returns an object and so some casting is required to make this work eg:

      int[] myInts = new int[] { 1, 2, 3, 4, 5 };
 
      int[] myInts2 = (int[])myInts.Clone();


The CopyTo is simillar but this copies elements into an existing array.  It copies all elements from the instance array into another existing array starting at a specified index.  Therefore the target array must be at least the same size as the instance array and the instance array must fit into the space available in the target array as determined by the specified index.  See the following code example.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
 
namespace Collections
{
    class ArrayCopyToExample
    {
        static void Main()
        {
            int[] myInts = new int[] {1, 2, 3, 4, 5};
 
            int[] myCopy = new int[10];
 
            Console.WriteLine("myCopy array");
           
            foreach (int i in myCopy)
            {
                Console.WriteLine(i);
            }
 
            myInts.CopyTo(myCopy, 3);
 
            Console.WriteLine();
 
            Console.WriteLine("myCopy array after CopyTo");
 
            foreach (int i in myCopy)
            {
                Console.WriteLine(i);
            }
 
            Console.Read();
        }
    }
}
 


Notice that we specify that the CopyTo should start at index 3 - so in the target array element 0, 1 and 2 will be left as is and then the copying will start at element 3.  This sample program yields the following results:

 

Another important point to notice about both of these methods is that they both create shallow copies.  In programming we have the terms shallow copy and deep copy.  A shallow copy just means that we have copied the reference only for reference objects so both variables will point to the same object.  Value types of course will create new copies.

So if we have an arry of reference types - StringBuilders for example - and we cerate copies using either Clone or CopyTo and we then then change something on the copied elements then this will affect the original elements too since they are both references to the same object on the heap.

To illustrate this lets have a look at the following 2 test programs - the first for Cloning and the second for CopyTo.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
 
namespace Collections
{
    class ArrayCloningStringBuilder
    {
        static void Main()
        {
            StringBuilder[] myStringBuilders = new StringBuilder[5];
 
            myStringBuilders[0] = new StringBuilder("AAAAA");
            myStringBuilders[1] = new StringBuilder("BBBBB");
            myStringBuilders[2] = new StringBuilder("CCCCC");
            myStringBuilders[3] = new StringBuilder("DDDDD");
            myStringBuilders[4] = new StringBuilder("EEEEE");
 
            Console.WriteLine("Original array (myStringBuilders)");
 
            foreach (StringBuilder sb in myStringBuilders)
            {
                Console.WriteLine(sb.ToString());
            }
 
            Console.WriteLine();
 
            StringBuilder[] myStringBuilders2 = (StringBuilder[])myStringBuilders.Clone();
 
            myStringBuilders2[0].Append("ZZZZZ");
 
            Console.WriteLine("Original array after clone created and changed (myStringBuilders)");
           
            foreach (StringBuilder sb in myStringBuilders)
            {
                Console.WriteLine(sb.ToString());
            }
 
            Console.WriteLine();
 
            Console.WriteLine("Cloned array after clone created and changed (myStringBuilders2)");
           
            foreach (StringBuilder sb in myStringBuilders2)
            {
                Console.WriteLine(sb.ToString());
            }
 
            Console.Read();
        }
    }
}

 
The output for this one looks like this and we can see that indeed the elements are shallow.

And here is a simillar program but using CopyTo

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
 
namespace Collections
{
    class ArrayCopyToStringBuilder
    {
        static void Main()
        {
            StringBuilder[] myStringBuilders = new StringBuilder[5];
            StringBuilder[] myStringBuilders2 = new StringBuilder[10];
 
            myStringBuilders[0] = new StringBuilder("AAAAAA");
            myStringBuilders[1] = new StringBuilder("BBBBBB");
            myStringBuilders[2] = new StringBuilder("CCCCCC");
            myStringBuilders[3] = new StringBuilder("DDDDDD");
            myStringBuilders[4] = new StringBuilder("EEEEEE");
 
            myStringBuilders2[0] = new StringBuilder("XXXXX");
            myStringBuilders2[1] = new StringBuilder("XXXXX");
            myStringBuilders2[2] = new StringBuilder("XXXXX");
            myStringBuilders2[3] = new StringBuilder("XXXXX");
            myStringBuilders2[4] = new StringBuilder("XXXXX");
            myStringBuilders2[5] = new StringBuilder("XXXXX");
            myStringBuilders2[6] = new StringBuilder("XXXXX");
            myStringBuilders2[7] = new StringBuilder("XXXXX");
            myStringBuilders2[8] = new StringBuilder("XXXXX");
            myStringBuilders2[9] = new StringBuilder("XXXXX");
 
            Console.WriteLine("Original Array (myStringBuilders)");
 
            foreach (StringBuilder sb in myStringBuilders)
            {
                Console.WriteLine(sb.ToString());
            }
 
            Console.WriteLine();
 
            Console.WriteLine("Original Array (myStringBuilders2)");
 
            foreach (StringBuilder sb in myStringBuilders2)
            {
                Console.WriteLine(sb.ToString());
            }
 
            myStringBuilders.CopyTo(myStringBuilders2, 3);
 
            Console.WriteLine();
 
            Console.WriteLine("myStringBuilders2 Array after CopyTo");
 
            foreach (StringBuilder sb in myStringBuilders2)
            {
                Console.WriteLine(sb.ToString());
            }
 
            myStringBuilders2[5].Append("ZZZZZ");
 
            Console.WriteLine();
 
            Console.WriteLine("Original myStringBuilders Array after CopyTo And element changed");
 
            foreach (StringBuilder sb in myStringBuilders)
            {
                Console.WriteLine(sb.ToString());
            }
 
            Console.WriteLine();
 
            Console.WriteLine("myStringBuilders2 Array after CopyTo And element changed");
 
            foreach (StringBuilder sb in myStringBuilders2)
            {
                Console.WriteLine(sb.ToString());
            }
 
            Console.Read();
        }
    }
}


And again the resuls shown below tell us that this too yields a shallow copy.

 

There are of course many more methods for the System.Array class - especially with the introduction of extension methods and Linq but that is another story.

We should now move on and look at the next collection class which is the ArrayList:

View the next part of this article on the ArrayList