Assembly binding Closure discovery tool

This is a tool I use to figure out the binding closure of one or many assemblies. Per request, I post the source code here.

It is provided as it is. I did not do any significant testing.

Sample output:

F:\Code\closure>more 1.txt
system, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089

F:\Code\closure>closure 1.txt
Initial assemblies are :
1: system, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089

Binding closures are
1: Microsoft.JScript, Version=8.0.1200.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
Assembly is in GAC.
2: Microsoft.Vsa, Version=8.0.1200.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
Assembly is in GAC.
3: mscorlib, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
Assembly is in GAC.
4: System, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
Assembly is in GAC.
5: System.Security, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
Assembly is in GAC.
6: System.Xml, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
Assembly is in GAC.

Here is the source code:

F:\Code\closure>more closure.cs

using System;
using System.IO;
using System.Reflection;
using System.Runtime.Remoting;
using System.Collections;
using System.Text;

class Closure
{
public static void Main(String[] argv)
{
if (argv.Length != 1)
{
Console.WriteLine("Usage: Closure AsmList.txt");
Console.WriteLine("AsmList.txt contains full display names of starting assemblies.");
Console.WriteLine("One assemblies per line.");
return;
}

        try
{
ArrayList asms = new ArrayList(256);

            using (StreamReader sr = new StreamReader(argv[0]))
{
String line = null;

                while((line = sr.ReadLine()) != null)
{
if (line != "") {
asms.Add(line);
}
}
}

            Closure closure = new Closure(asms);
closure.Run();
closure.ShowResult();
}
catch(Exception e)
{
Console.WriteLine("Exception: {0}", e.Message);
}
}

    public Closure(ArrayList asms)
{
names = new Queue(256);
results = new Hashtable(null,CaseInsensitiveComparer.DefaultInvariant);
failed = new ArrayList(256);

        initAsms = asms;

        foreach (String s in asms)
{
names.Enqueue(s);
}
}

    void Run()
{
Hashtable probed = new Hashtable(null,CaseInsensitiveComparer.DefaultInvariant);

        Assembly asm = null;
while (names.Count != 0) {
Object o = names.Dequeue();
String s = o as String;
if (s != null) {
if (probed.Contains(s)) {
continue;
}

                probed.Add(s, s);

                try {
asm = Assembly.Load(s);
}
catch(Exception e) {
if ((e is FileNotFoundException) || (e is FileLoadException)) {
failed.Add(s);
continue;
}
else {
throw;
}
}

                String asmname = asm.FullName;
if (!results.Contains(asmname)) {
results.Add(asmname, asm);
}
AssemblyName[] asmDepNames = asm.GetReferencedAssemblies();
foreach(AssemblyName name in asmDepNames) {
asmname = name.FullName;
if (!probed.Contains(asmname)) {
names.Enqueue(asmname);
}
}
}
}
}

    void ShowResult()
{
initAsms.Sort();
int i = 0;
Console.WriteLine("Initial assemblies are :");
foreach (Object o in initAsms) {
String s = o as String;
if (s != null) {
i++;
Console.WriteLine("\t{0}: {1}", i, s);
}
}

        Console.WriteLine("\nBinding closures are");
ICollection keys = results.Keys;
String[] sKeys = new String[keys.Count];
keys.CopyTo(sKeys, 0);

        Array.Sort(sKeys, CaseInsensitiveComparer.DefaultInvariant);
for(i=0; i< sKeys.Length;i++) {
Console.WriteLine("\t{0}: {1}", i+1, sKeys[i]);
Object o = results[sKeys[i]];
Assembly asm = o as Assembly;
if (asm != null) {
if (asm.GlobalAssemblyCache) {
Console.WriteLine("\tAssembly is in GAC.");
}
else {
Console.WriteLine("\tAssembly is not in GAC.");
}
}
}

        if (failed.Count != 0) {
failed.Sort();
Console.WriteLine("\nFollowing assemblies cannot be found :");
i = 0;
foreach (Object o in failed) {
String s = o as String;
if (s != null) {
i++;
Console.WriteLine("\t{0}: {1}", i, s);
}
}
}
}

    private ArrayList initAsms;
private Queue names;
private Hashtable results;
private ArrayList failed;
}