#729 – Dumping Out All Types in .NET Framework, part II

Here’s an updated copy of the code that iterates through all .NET assemblies, dumping out type information.  This code iterates through all .NET assemblies and dumps out a master list of all types, organized by namespace.  Information about the type members is dumped out for each type and everything is written to a file.  The code has also been updated to descend into all sub-directories of the .NET runtime directory.

When I run this against .NET 4.0.30319, I get a total of 50,380 types, in 872 namespaces.

    class Program
    {
        static void Main()
        {
            int totalNamespaces = 0;
            int totalTypes = 0;

            AppDomain.CurrentDomain.ReflectionOnlyAssemblyResolve += CurrentDomain_ReflectionOnlyAssemblyResolve;

            SortedList<string, SortedList<string, Type>> fullList =
                new SortedList<string, SortedList<string, Type>>();

            DirectoryInfo di = new DirectoryInfo(RuntimeEnvironment.GetRuntimeDirectory());
            foreach (FileInfo fi in di.GetFiles("*",SearchOption.AllDirectories))
            {
                Trace.WriteLine("File: {0}", fi.FullName);
                try
                {
                    Assembly assem = Assembly.LoadFrom(fi.FullName);

                    if (assem != null)
                    {
                        ExtractListOfTypes(assem, ref fullList, ref totalNamespaces, ref totalTypes);
                    }
                }
                catch (Exception xx)
                {
                    Trace.WriteLine(string.Format("EXCEPTION on {0}: {1}", fi.FullName, xx.ToString()));
                }
            }

            DumpTypeList(fullList, totalNamespaces, totalTypes);
        }

        static Assembly CurrentDomain_ReflectionOnlyAssemblyResolve(object sender, ResolveEventArgs args)
        {
            return Assembly.ReflectionOnlyLoad(args.Name);
        }

        private static void ExtractListOfTypes(Assembly assem, ref SortedList<string, SortedList<string, Type>> theList,
            ref int totalNamespaces, ref int totalTypes)
        {
            if (theList == null)
                throw new Exception("Uninitialized list");

            foreach (Type t in assem.GetTypes())
            {
                string theNamespace = t.Namespace != null ? t.Namespace : "(global)";

                // Add namespace if it's not already in list
                if (!theList.ContainsKey(theNamespace))
                {
                    theList.Add(theNamespace, new SortedList<string, Type>());
                    totalNamespaces++;
                }

                // And add type under appropriate namespace
                if (!theList[theNamespace].ContainsKey(t.FullName))
                {
                    theList[theNamespace].Add(t.FullName, t);
                    totalTypes++;
                }
            }

            return;
        }

        private static void DumpTypeList(SortedList<string, SortedList<string, Type>> theList,
                                         int totalNamespaces, int totalTypes)
        {
            using (StreamWriter writer = new StreamWriter(@"C:\Test\AllTypes.txt"))
            {
                writer.WriteLine(string.Format("Total Namespaces: {0}", totalNamespaces));
                writer.WriteLine(string.Format("Total Types: {0}", totalTypes));

                foreach (KeyValuePair<string, SortedList<string, Type>> kvp in theList)
                {
                    writer.WriteLine(string.Format("Namespace: [{0}]", kvp.Key));

                    foreach (KeyValuePair<string, Type> kvpInner in kvp.Value)
                    {
                        Type t = (Type)kvpInner.Value;
                        writer.WriteLine(string.Format("  Type: [{0}] ({1})", t.FullName, TypeIndicator(t)));
                        DumpTypeInfo(t, writer);
                    }

                    writer.WriteLine();
                }
            }
        }

        private static void DumpTypeInfo(Type t, StreamWriter writer)
        {
            writer.WriteLine(string.Format("    Assembly: {0}", t.Assembly.FullName));
            if (t.BaseType != null)
                writer.WriteLine(string.Format("    Base Type: {0}", t.BaseType.FullName));

            MemberInfo[] members = t.GetMembers();
            if (members.Length > 0)
            {
                writer.WriteLine("    Members:");
                foreach (MemberInfo mi in members)
                {
                    writer.WriteLine(string.Format("      {0}  ({1})", mi.ToString(), mi.MemberType));
                }
            }
        }

        private static string TypeIndicator(Type t)
        {
            string typeIndicator = "?";

            if ((t.BaseType != null) &&
                (t.BaseType.FullName == "System.MulticastDelegate"))
                typeIndicator = "delegate";

            else if (t.IsClass)
            {
                if (t.IsNested)
                    typeIndicator = "Nested class";
                else
                    typeIndicator = "class";
            }
            else if (t.IsInterface)
                typeIndicator = "interface";

            else if (t.IsValueType)
                typeIndicator = "struct";

            else if (t.IsEnum)
                typeIndicator = "enum";

            return typeIndicator;
        }
    }
Advertisements

About Sean
Software developer in the Twin Cities area, passionate about .NET technologies. Equally passionate about my own personal projects related to family history and preservation of family stories and photos.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: