1. Technology

How to use collections in C#

Using the List<T> class

By

List Image

In the previous tutorial, we looked at an static methods aka methods and in this one is the first of several on collections in C#.

In this and the following tutorials I'll show how to use several of the Collection Classes.

Arrays are Ok But...

Arrays have their uses when the data is fixed size. When it isn't then that's when collection types becomes important. So what are the available collection types?

There are several classes.

  • Generic Classes- these are type safe and store the object as the particular type. These include Dictionary, HashSet<T>, LinkedList<T>, List<T>, Queue<T>, SortedDictionary, SortedList, SortedeSet<T> and Stack<T>.

  • Non Generic Classes. Not so safe these store your objects as type object and require casting to retrieve the original type. ArrayList, BitArray, HashTable, Queue and Stack.

  • Concurrent Collection Classes. These are thread safe and only available since .NET 4. These include BlockingCollection<T>, ConcurrentBag<T>, ConcurrentDictionary, ConcurrentQueue<T>, ConcurrentStack<T>, OrderablePartitioner, Partitioner<T> and Partitioner

Of these the generic collection classes are generally the best. The non generic classes are older and code using those is not as clean. The concurrent collections and the Synchronized classes in the Generic Collections are for more specialized use so I'll return to them in the future.

Generic Collection Classes

The one we'll start with is the List<T>. I've used this extensively and it's very useful. If you know C++, think of it as the equivalent of the vector class. I want to show how to use it but also peek a little behind the curtain to show a little how it works.

The <T> in List<T> and other classes means that it can take any type T. You can have a list of ints, of string or of any class.

Does the List hold a copy of the item or a reference to it?

If it is a value item like a struct then it makes a copy of it. For anything else, it is a reference.

I used List<T> in a dog show application for shows run under the UK Kennel Club rules that I developed with a friend. It takes dogs and owners and generates the draws and show catalog.

There's a DogClass for each dog and a DogList Class which uses internally a List. The DogShow class holds a DogList for all dogs and each owner has a DogList of their dogs.

This DogList is used in other parts of the program. For instance all the dogs are divided into Classes (beginner etc) and when there are a large number of dogs each class is split into smaller parts. A DogLIst is used to hold the dogs in each part and a second one to hold the 10 dogs that are Drawn, to walk around in front of judges.

I've taken the DogClass and DogList classes and put them in a small program to show them being used.

Notes on this

Using a list is pretty straightforward, you can add things to it, or remove them, sort it, return a read only version, do a binary search, access it the individualitems by items[], search using Find, FindIndexz, Find and much more. See the documentation on List<T> for details.

But your code will get messy so why not wrap it up in a class like I did with DogClass(). I've made the list public but readonly, so if I need to access dogs.dogs, I can. That can be slightly dangerous though because it allows code like this which removes all dogs that are not bitches.

dogs.Dogs.RemoveAll(adog => adog.IsBitch == false);

That's in the code but commented out. Try uncommenting it to see what happens!

I've made the dogs the default using the this[int i] indexer so they can be accessed by index like this:

Console.WriteLine("Dog[1] is {0}", dogs[1]);

The example creates a DogList and adds four dogs to it using the Constructor initialization of members then outputs information. You can see it run on ideone.com

var dogs = new DogList();
dogs.AddDog(new DogClass(){Name=@"Rufus",Breed="Minature Poodle",IsBitch = false,Age=4});
dogs.AddDog(new DogClass() {Name = @"Monty", Breed = "Minature Poodle", IsBitch = false,Age=5 });
dogs.AddDog(new DogClass() { Name = @"Sam", Breed = "Standard Poodle", IsBitch = false,Age=12 });
dogs.AddDog(new DogClass() { Name = @"Judy", Breed = "Afghanistan", IsBitch = true,Age=3 });

To have the foreach code and LINQ work, it's necessary to add an enumerator for the collection. This looks like this:

public IEnumerator<DogClass> GetEnumerator()
{
    foreach (var d in dogs)
        yield return d;
}

Though it can be reduced to a single line LINQ statement as I've done in the example code.

A Comparator Function for Sorting

If you'd like your list to be sorted, you have to add a comparator function to pass to the List.Sort() method. There's no way this function can know which member to use to sort or even how to sort on that member unless you tell it.

So by adding your own function like this, you can then call sort(). It uses String.CompareTo to do the comparison and so must return an int.

public int MySortFunction(DogClass dog1, DogClass dog2)
{
    return dog1.Name.CompareTo(dog2.Name) ;
}

public void Sort()
{
    dogs.Sort(MySortFunction) ;
}

So just pass the MySortFunction to dogs.Sort( ) and the list is sorted.

In DogClass, I use a static member iddog, initialized in a static constructor. This is incremented whenever an instance of a dog is created so the Iddog of each is unique.

In the next C# tutorial I'll look at the Dictionary class. This is often called Map in other programming languages.

©2014 About.com. All rights reserved.