My god what was I thinking, using StringCollection over ArrayList?
I don't know why I figured the StringCollection might actually be more performant than the ArrayList. I guess I assumed this was the one case where they would emit a strongly typed collection that was based on ArrayList, but was strongly typed on the back-end. However, looking at the rotor source, all it does is inherit from ArrayList and really doesn't provide any added value (except that you don't have to do the string cast when pulling elements out).
Doing a basic timed iteration over a StringCollection using a large number of elements (in the millions), it was almost twice as fast to just use the ArrayList and forget about StringCollection altogether. Unless you want a collection that is easy to use from the standpoint of not having to do the string casts, I would highly recommend against the StringCollection. It just doesn't buy you anything. I would highly recommend using the ArrayList source code from the rotor code-base to write your own strongly typed collection though. You have to remember how much time went into setting the initialCapacity and determining the growth metrics for the ArrayList thanks to the performance team at MS. They made the ArrayList one of the best collections available.
I've heard of some decent tools for developing strongly typed collections as well. CodeSmith comes to mind, so you might want to check those out. All of these things become null and void (for the most part with some exceptions) when generics hit the shelves since generics make it easy to write strongly typed collections and most of the collections classes/interfaces have already undergone a generics overhaul and are quite performant. If you'd like to run the numbers for yourself of ArrayList versus StringCollection you can just compile the below test class. Enjoy.
using System;
using System.Collections;
using System.Collections.Specialized;
public class StringCollectionTest {
private static void Main(string[] args) {
DateTime start, end;
int iterations = int.Parse(args[0]);
/*
Get all the strings into a strongly typed
array so we don't incur the hit of placing
them into the string table during the actual
usage of the collections.
*/
string[] strings = new string[iterations];
for(int i = 0; i < strings.Length; i++) {
strings[i] = i.ToString();
}
/*
Create a string collection and add all of
the strings. Note this is just adding the
strings to an ArrayList underneath.
Once done, do a CopyTo our newly allocated
strongly typed string[].
*/
StringCollection coll = new StringCollection();
start = DateTime.Now;
for(int i = 0; i < strings.Length; i++) {
coll.Add(strings[i]);
}
string[] collStrings = new string[strings.Length];
coll.CopyTo(collStrings, 0);
end = DateTime.Now;
Console.WriteLine("String Collection: {0}", end - start);
/*
Create an ArrayList. Add all of the strings
to the collection.
Once done, do a ToArray, which internally creates
a newly allocated array of the appropriate length
and type and returns it after copying all elements
into place.
*/
ArrayList coll2 = new ArrayList();
start = DateTime.Now;
for(int i = 0; i < strings.Length; i++) {
coll2.Add(strings[i]);
}
string[] coll2Strings = (string[]) coll2.ToArray(typeof(string));
end = DateTime.Now;
Console.WriteLine("ArrayList : {0}", end - start);
}
}