The idea behind collections is concurrently convenient and fraught with potential conversion problems. Collections are designed to store all things given to them as objects and therefore filling a collection is cake.
ArrayList MyList = new ArrayList();
MyList.Add("10"); //wait this is a string ... but it is perfectly legal as everything is stored as an object.
The fundamental idea is you can place multiple variable types in a single collection conveniently, without regard for all that is type safe or type sane. The problem is ultimately revealed when we unwrap our collection and expose it to the real type safe world of .NET programming.
We end up with:
int int8 = (int)MyList;
int int9 = (int)MyList;
int int10 = (int)MyList; //but wait this is a string!
…but the compiler can never know because collections are all objects and this will not become apparent until run time (usually in QA or worse yet in Production).
This simple example now requires the programmer to continually track what types are associated with which element of the ArrayList which invariably leads to complex and custom type checking solutions.
.NET 2.0 to the rescue:
Our friends at Microsoft have provided us with a Generic List (Systems.Collections.Generic) that can be type safe. Our code now becomes
List<int> MyNewList = new List<int>() //<int> tells the compiler that this is a generic collection of type int.
MyNewList.Add("10"); \\this is still a string but this can be caught immediately
The problematic line of code can now be caught safely by the compiler before ever going to QA, production, or even you own unit testing.