#1,144 – Getting Type Information about a Generic Type

You can use the typeof operator to get information about a particular type.  The operator returns an instance of the Type class, which you can then query to get info about the type.

You can get type information about generic types in two different ways.  You can use the name of the type with empty angle brackets to get information about the generic type.  Or you can supply type arguments to get information about a particular constructed type.

        private static void DumpInfoForType(Type t)
        {
            Console.WriteLine("Type {0}:", t.Name);
            Console.WriteLine("  IsGenericType: {0}", t.IsGenericType);
            Console.WriteLine("  IsGenericTypeDefinition: {0}", t.IsGenericTypeDefinition);
            Console.WriteLine("  IsConstructedGenericType: {0}", t.IsConstructedGenericType);
            Console.WriteLine("  ContainsGenericParameters: {0}", t.ContainsGenericParameters);

            if (t.IsConstructedGenericType)
            {
                foreach (Type targ in t.GenericTypeArguments)
                    Console.WriteLine("Arg: {0}", targ.Name);
            }
        }

        static void Main(string[] args)
        {
            DumpInfoForType(typeof(Pile<>));
            DumpInfoForType(typeof(Pile<Dog>));
        }

The first type is a generic type definition with generic parameters. The second is a constructed generic type with a Dog argument.

1144-001

Advertisement

#731 – Getting Information About the Members of a Class

You can use the Type.GetMembers method to get information about all public members in a type.  GetMembers returns an array of MemberInfo objects, each of which can be used to get details about one of the members of the type.

Here’s a sampling of some of the information that you can get:

            MemberInfo[] members = typeof(Dog).GetMembers();

            if (members != null)
                foreach (MemberInfo mi in members)
                {
                    Console.WriteLine(mi.Name);
                    Console.WriteLine(string.Format("  MemberType: {0}", mi.MemberType));

                    object[] attributes = mi.GetCustomAttributes(false);
                    if ((attributes != null) && (attributes.Length > 0))
                    {
                        Console.Write("  Attributes: ");
                        foreach (object attr in attributes)
                            Console.Write(string.Format("{0} ", attr.ToString()));
                        Console.WriteLine();
                    }

                    // Get subtype-specific information
                    switch (mi.MemberType)
                    {
                        case MemberTypes.Constructor:
                            DumpConstructorInfo((ConstructorInfo)mi);
                            break;

                        case MemberTypes.Event:
                            DumpEventInfo((EventInfo)mi);
                            break;

                        case MemberTypes.Method:
                            DumpMethodInfo((MethodInfo)mi);
                            break;
                    }

                    Console.WriteLine();
                }
        private static void DumpConstructorInfo(ConstructorInfo ci)
        {
            Console.WriteLine(string.Format("  Calling Convention: {0}", ci.CallingConvention));

            StringBuilder sbInfo = new StringBuilder("  ");
            if (ci.IsAbstract) sbInfo.Append("Abstract ");
            if (ci.IsGenericMethod) sbInfo.Append("GenericMethod ");
            if (ci.IsHideBySig) sbInfo.Append("HideBySig ");
            if (ci.IsPrivate) sbInfo.Append("Private ");
            if (ci.IsPublic) sbInfo.Append("Public ");
            if (ci.IsStatic) sbInfo.Append("Static ");
            if (ci.IsVirtual) sbInfo.Append("Virtual ");

            if (sbInfo.Length > 2)
                Console.WriteLine(sbInfo);
        }

        private static void DumpEventInfo(EventInfo ei)
        {
            Console.WriteLine(string.Format("  Event Handler Type: {0}", ei.EventHandlerType.Name));
            if (ei.IsMulticast) Console.WriteLine("  IsMulticast");
        }

        private static void DumpMethodInfo(MethodInfo mi)
        {
            Console.WriteLine(string.Format("  Calling Convention: {0}", mi.CallingConvention));

            StringBuilder sbInfo = new StringBuilder("  ");
            if (mi.IsAbstract) sbInfo.Append("Abstract ");
            if (mi.IsGenericMethod) sbInfo.Append("GenericMethod ");
            if (mi.IsHideBySig) sbInfo.Append("HideBySig ");
            if (mi.IsPrivate) sbInfo.Append("Private ");
            if (mi.IsPublic) sbInfo.Append("Public ");
            if (mi.IsStatic) sbInfo.Append("Static ");
            if (mi.IsVirtual) sbInfo.Append("Virtual ");

            ParameterInfo[] paraminfo = mi.GetParameters();
            if ((paraminfo != null) && (paraminfo.Length > 0))
            {
                Console.Write("  Parameters: ");
                foreach (ParameterInfo pi in paraminfo)
                {
                    Console.Write(string.Format("{0} ({1})  ", pi.Name, pi.ParameterType.Name));
                }
                Console.WriteLine();
            }
        }

731-001

#728 – Dumping Out All Types in the .NET Framework

Here’s some code that looks through all assemblies in the .NET Framework directory and uses to reflection to dump out all of the types, organized by namespace.

        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())
            {
                try
                {
                    Assembly assem = Assembly.LoadFrom(fi.FullName);

                    if (assem != null)
                    {
                        ExtractListOfTypes(assem, ref fullList, ref totalNamespaces, ref totalTypes);
                    }
                }
                catch { }
            }

            Console.WriteLine(string.Format("{0} types, in {1} namespaces", totalTypes, totalNamespaces));
            DumpTypeList(fullList);
        }

        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)
        {
            foreach (KeyValuePair<string,SortedList<string,Type>> kvp in theList)
            {
                Console.WriteLine(string.Format("Namespace: [{0}]", kvp.Key));

                foreach (KeyValuePair<string, Type> kvpInner in kvp.Value)
                {
                    Console.WriteLine(string.Format("  Type: [{0}]", ((Type)kvpInner.Value).FullName));
                }

                Console.WriteLine();
            }
        }

When I run this against .NET 4.0.30319, I get a total of 40,166 types, in 657 namespaces.

728-001

#727 – Get a List of All Namespaces in an Assembly

While you can’t explicitly get a list of all namespaces within a .NET assembly, you can iterate through all types in the assembly and build up a list of namespaces.

Below is some sample code that organizes all types in an assembly, by namespace.

        static void Main()
        {
            // Build list of all types :
            //   SortedList<namespace-name, SortedList<type-name, Type>>

            SortedList<string, SortedList<string, Type>> myTypeList =
                ExtractListOfTypes(Assembly.GetExecutingAssembly());

            DumpTypeList(myTypeList);
        }

        private static SortedList<string, SortedList<string, Type>> ExtractListOfTypes(Assembly assem)
        {
            SortedList<string, SortedList<string, Type>> theList =
                new SortedList<string, SortedList<string, Type>>();

            foreach (Type t in assem.GetTypes())
            {
                // Add namespace if it's not already in list
                if (!theList.ContainsKey(t.Namespace))
                    theList.Add(t.Namespace, new SortedList<string, Type>());

                // And add type under appropriate namespace
                theList[t.Namespace].Add(t.FullName, t);
            }

            return theList;
        }

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

                foreach (KeyValuePair<string, Type> kvpInner in kvp.Value)
                {
                    Console.WriteLine(string.Format("  Type: [{0}]", ((Type)kvpInner.Value).FullName));
                }

                Console.WriteLine();
            }
        }

727-001

#726 – Listing all Types within a Namespace

You can’t directly list out all types within a namespace.  But you can get all types within a particular assembly and then filter out only the types that match a particular namespace.

        static void Main()
        {
            // Dump all types from in a specified namespace
            DumpTypesForNamespace(Assembly.GetExecutingAssembly(), "ConsoleApplication1");
            DumpTypesForNamespace(Assembly.GetExecutingAssembly(), "ConsoleApplication1.Dog");

            int i = 1;
        }

        private static void DumpTypesForNamespace (Assembly assem, string theNamespace)
        {
            Console.WriteLine(string.Format("[{0}]", theNamespace));

            foreach (Type t in assem.GetTypes())
            {
                if (t.Namespace == theNamespace)
                {
                    string dump =
                        string.Format("{0}\n  ({1} in {2})\n", t.FullName, TypeIndicator(t), t.Namespace);

                    Console.WriteLine(dump);
                }
            }
            Console.WriteLine("\n");
        }

        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;
        }

726-002

#725 – Dumping Out a List of Types in an Assembly

You can use reflection to get a list of all types in an assembly.  Each type is represented by an instance of the Type class, which you can then query to get information about the type.

Below is a code sample that dumps out all types defined in the running assembly.  Notice that we identify each type as one of the five custom types that you can define.

        static void Main()
        {
            foreach (Type t in Assembly.GetExecutingAssembly().GetTypes())
            {
                string dump =
                    string.Format("{0}\n  ({1} in {2})\n", t.FullName, TypeIndicator(t), t.Namespace);

                Console.WriteLine(dump);
            }
        }

        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;
        }

#453 – Use Reflection to Get a List of Interfaces that a Class Implements

You can query an object at runtime, using reflection, to get information about its members.  This includes the interfaces that the object’s class implements.

            Cow bessie = new Cow("Bessie", 4);

            // Use reflection to dump out information about
            //   Bessie's interfaces and the methods in
            //   each interface.
            Type t = bessie.GetType();
            foreach (Type iType in t.GetInterfaces())
            {
                Console.WriteLine("Interface [{0}]:", iType.Name);
                foreach (MemberInfo minfo in iType.GetMembers())
                {
                    Console.WriteLine("  {0}", minfo.Name);
                }
            }