Access Type Information using Reflection in C#


Reflection is the process of obtaining information about a type at runtime using the metadata present in .NET assemblies. Using reflection you can investigate the types available in a .NET assembly and also members present in each type. You can also load an assembly at runtime, create objects of a type and invoke members using reflection.

In this article we will concentrate on how to get the type information like methods, properties, fields, constructors, interfaces and events available on the type.

System.Reflection namespace defined in mscorlib.dll contains most of the classes required to support runtime type discovery.

List of classes holding type member information are shown in the below table.

Name

Description

EventInfo

Abstract class holding the event information, it provides attributes of the event and metadata.

FieldInfo

Abstract class holding the field information, it provides attributes of the field and metadata information

MethodInfo

Abstract class holding the method information, provides attributes and metadata of the method.

PropertyInfo

Provides access to property metadata. This class is abstract.

ParameterInfo

Provides access to parameter metadata.

MemberInfo

Abstract class providing access to member metadata. This is abstract class which defines common behavior for EventInfo, FieldInfo, MethodInfo and PropertyInfo.

ConstructorInfo

Abstract class that provides access to constructors metadata.

 

System.Type Class

System.Type is the main class used to investigate the metadata of a type and its members.

Some of the important members of System.Type are listed in the below table.

Member

Description

IsAbstract

Property to check if the type is abstract.

IsSealed

Property to check if the type is sealed.

IsEnum

Property to check if the type is enum

IsInterface

Property to check if the type is interface.

IsValueType

Property to check if the type is a value type.

GetType()

Gets the type of the object.

GetConstructors()

Get the constructors list as ConstructorInfo array.

GetEvents()

Get the events list as EventInfo array.

GetFields()

Gets the fields list as FieldInfo array.

GetInterfaces()

Gets the interface list as Type array.

GetProperties()

Gets the properties list as PropertyInfo array.

GetMethods()

Gets the methods list as MethodInfo array.

GetMembers()

Gets the members list as MemberInfo array.

 

The methods mentioned above have overloads to filter the results, there are also methods to get information about a single member by the passing the member name as parameter. Please look at Microsoft.NET documentation to see the complete list of the members provided by System.Type type.

Getting Type Reference

There are different ways of getting the type reference. If you already have an object and want to get its metadata, you can directly call GetType() method on the object.

    ClassA classAObject = new ClassA();
    Type type = classAObject.GetType();

If the type is available in the current project as reference or if the type is defined within the current project you can use typeof operator.

    Type type = typeof(ClassA);

If the type is not available at compile time, ie type is part of an external assembly which is not referenced in current project, then Type.GetType method is used to get the type metadata. You have to pass the full name of the type and assembly name separated by comma, as a string to the GetType method.

    Type type = Type.GetType("CSharp_Samples.ClassA, CSharp_Samples");

We will be using the below defined ClassA and InterfaceA in the code samples further. ClassA has a variety of members defined and also implements InterfaceA.

    public interface InterfaceA
    {
        void MethodA();
    }

    /// <summary>
    /// Class showing the usage of different Members.
    /// </summary>
    public class ClassA : InterfaceA
    {
        /// <summary>
        /// Private Field
        /// </summary>
        private int counter = 0;

        /// <summary>
        /// Public Constant
        /// </summary>
        public const string Name = "Dominic";

        /// <summary>
        /// Private Field Array.
        /// </summary>
        private int[] numbers = new int[] { 10, 20, 30, 22, 15 };

        /// <summary>
        /// Property
        /// </summary>
        public int Counter
        {
            get
            {
                return this.counter;
            }

            set
            {
                // Validation done before changing the counter.
                if ((value > 0) && (value != this.counter))
                {
                    this.counter = value;

                    // Notification sent if counter is changed.
                    this.CounterChangeNotifier(this, counter);
                }
            }
        }

        /// <summary>
        /// Public Method.
        /// </summary>
        public void PrintInfo()
        {
            Console.WriteLine("Printing...");
        }

        /// <summary>
        /// Event.
        /// </summary>
        public event EventHandler<int> CounterChangeNotifier;

        /// <summary>
        /// Indexer
        /// </summary>
        /// <param name="index"></param>
        /// <returns></returns>
        public int this[int index]
        {
            get
            {
                return numbers[index];
            }
        }

        /// <summary>
        /// Constructor.
        /// </summary>
        public ClassA()
        {
            this.counter = 0;
        }

        /// <summary>
        /// Constructor with Parameter.
        /// </summary>
        /// <param name="counter"></param>
        public ClassA(int counter)
        {
            this.counter = counter;
        }

        /// <summary>
        /// Destructor.
        /// </summary>
        ~ClassA()
        {
            // Release any resouces here.
        }

        /// <summary>
        /// Private nested class.
        /// </summary>
        private class NestedClass
        {
            // Class definition goes here.
        }

        /// <summary>
        /// Implementing interface method.
        /// </summary>
        public void MethodA()
        {
            // method implementation here.
        }
    }

 

Reflection on Constructors

GetConstructors() instance method of type is used to get the list of constructors in a type. It returns an array of ConstructorInfo objects. GetParameters() method in the ConstructorInfo class returns the parameters of a constructor.

        // Get the type information of ClassA in namespace CSharp_Samples.
        // ClassA is defined in assembly CSharp_Samples
        // You have to pass class name with namespace and library name separated by comma.
        Type type = Type.GetType("CSharp_Samples.ClassA, CSharp_Samples");
            
        // Get all the constructors.
        ConstructorInfo[] constructors = type.GetConstructors();
        Console.WriteLine("Printing Constructor Information.");

        // Printing the constructor count.
        Console.WriteLine(string.Format("Total Number of Constructors - {0}", constructors.Length));

        // Foreach constructor print constructor definition and its parameters.
        foreach(ConstructorInfo constructor in constructors)
        {
            Console.WriteLine(constructor.ToString());
            ParameterInfo[] parameters = constructor.GetParameters();

            if ((parameters != null) && (parameters.Length != 0))
            {
                Console.WriteLine("Parameters...");
                foreach (ParameterInfo parameter in parameters)
                {
                    Console.WriteLine(parameter.ParameterType + " " + parameter.Name);
                }
            }                
        }

 

Reflection on Fields

GetFields() instance method of Type is used to get all the fields supported by the type, it returns an array of FieldInfo objects.

        // Get the type information of ClassA in namespace CSharp_Samples.
        // ClassA is defined in assembly CSharp_Samples
        // You have to pass class name with namespace and library name separated by comma.
        Type type = Type.GetType("CSharp_Samples.ClassA, CSharp_Samples");
        
        // Get all the Fields.
        FieldInfo[] fields = type.GetFields();
        Console.WriteLine();
        Console.WriteLine("Printing Field Information.");

        if ((fields == null) || (fields.Length == 0))
        {
            Console.WriteLine("No fields in the Type.");
        }
        else
        {
            Console.WriteLine(string.Format("Total Number of Fields - {0}", fields.Length));
            foreach (FieldInfo field in fields)
            {
                // Display Field Type and Name
                Console.WriteLine(field.FieldType + " " + field.Name);                    
            }
        }

 

Reflection on Methods

GetMethods() instance method of type is used to get all the methods in the type, it returns an array of MethodInfo objects. In the below code snipped we are filtering the methods returned by using an overloaded method of GetMethods() which takes BindingFlags as input.

        // Get the type information of ClassA in namespace CSharp_Samples.
        // ClassA is defined in assembly CSharp_Samples
        // You have to pass class name with namespace and library name separated by comma.
        Type type = Type.GetType("CSharp_Samples.ClassA, CSharp_Samples");
        
        // Getting all the methods.
        // Passing filters to only return instance level, public methods which are defined in the type.
        // DeclareOnly gets only methods declared in current type, inherited methods are ignored.
        MethodInfo[] methods = type.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly);
        Console.WriteLine();
        Console.WriteLine("Printing Methods Information.");

        if ((methods == null) || (methods.Length == 0))
        {
            Console.WriteLine("No Methods in the Type.");
        }
        else
        {
            Console.WriteLine(string.Format("Total Number of Methods - {0}", methods.Length));
            foreach (MethodInfo method in methods)
            {

                Console.WriteLine(string.Format("Method Name - {0}", method.Name));
                Console.WriteLine(string.Format("Method Return Type - {0}", method.ReturnType));

                // Get the parameters.
                ParameterInfo[] parameters = method.GetParameters();

                if ((parameters != null) && (parameters.Length != 0))
                {
                    Console.WriteLine("Parameters of method.");

                    // Iterate through parameters and print return type and Name of the method.
                    foreach (ParameterInfo parameter in parameters)
                    {
                        Console.WriteLine(parameter.ParameterType + " " + parameter.Name);
                    }
                }               

            }
        }

 

Reflection on Interfaces.

GetInterfaces() instance method on type object gives all the interfaces implemented by the type as a type array.

        // Get the type information of ClassA in namespace CSharp_Samples.
        // ClassA is defined in assembly CSharp_Samples
        // You have to pass class name with namespace and library name separated by comma.
        Type type = Type.GetType("CSharp_Samples.ClassA, CSharp_Samples");
        
        // Getting all the interfaces.
        Type[] types = type.GetInterfaces();
        Console.WriteLine();
        Console.WriteLine("Printing Interfaces Information.");

        if ((types == null) || (types.Length == 0))
        {
            Console.WriteLine("No Interfaces implemented by the Type.");
        }
        else
        {
            Console.WriteLine(string.Format("Total Number of Interfaces - {0}", types.Length));

            // Iterate through all the interfaces. Print Name and IsInterface property.
            foreach (Type obj in types)
            {
                Console.WriteLine(obj.Name + " " + obj.IsInterface);
            }
        }

 

Complete Code Sample

Complete code of the examples used in this article is show below.

    public class TypeInformationUsingReflection
    {
        public static void Main()
        {

            // Get the type information of ClassA in namespace CSharp_Samples.
            // ClassA is defined in assembly CSharp_Samples
            // You have to pass class name with namespace and library name separated by comma.
            Type type = Type.GetType("CSharp_Samples.ClassA, CSharp_Samples");
                
            // Get all the constructors.
            ConstructorInfo[] constructors = type.GetConstructors();
            Console.WriteLine("Printing Constructor Information.");
    
            // Printing the constructor count.
            Console.WriteLine(string.Format("Total Number of Constructors - {0}", constructors.Length));
    
            // Foreach constructor print constructor definition and its parameters.
            foreach(ConstructorInfo constructor in constructors)
            {
                Console.WriteLine(constructor.ToString());
                ParameterInfo[] parameters = constructor.GetParameters();
    
                if ((parameters != null) && (parameters.Length != 0))
                {
                    Console.WriteLine("Parameters...");
                    foreach (ParameterInfo parameter in parameters)
                    {
                        Console.WriteLine(parameter.ParameterType + " " + parameter.Name);
                    }
                }                
            }
    
            // Get all the Fields.
            FieldInfo[] fields = type.GetFields();
            Console.WriteLine();
            Console.WriteLine("Printing Field Information.");
    
            if ((fields == null) || (fields.Length == 0))
            {
                Console.WriteLine("No fields in the Type.");
            }
            else
            {
                Console.WriteLine(string.Format("Total Number of Fields - {0}", fields.Length));
                foreach (FieldInfo field in fields)
                {
                    // Display Field Type and Name
                    Console.WriteLine(field.FieldType + " " + field.Name);                    
                }
            }

            // Get all the properties.
            PropertyInfo[] properties = type.GetProperties();
            Console.WriteLine();
            Console.WriteLine("Printing Properties Information.");

            if ((properties == null) || (properties.Length == 0))
            {
                Console.WriteLine("No Properties in the Type.");
            }
            else
            {
                Console.WriteLine(string.Format("Total Number of Properties - {0}", properties.Length));
                foreach (PropertyInfo property in properties)
                {
                    Console.WriteLine(property.ToString());
                }
            }

            // Getting all the methods.
            // Passing filters to only return instance level, public methods which are defined in the type.
            // DeclareOnly gets only methods declared in current type, inherited methods are ignored.
            MethodInfo[] methods = type.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly);
            Console.WriteLine();
            Console.WriteLine("Printing Methods Information.");
    
            if ((methods == null) || (methods.Length == 0))
            {
                Console.WriteLine("No Methods in the Type.");
            }
            else
            {
                Console.WriteLine(string.Format("Total Number of Methods - {0}", methods.Length));
                foreach (MethodInfo method in methods)
                {
    
                    Console.WriteLine(string.Format("Method Name - {0}", method.Name));
                    Console.WriteLine(string.Format("Method Return Type - {0}", method.ReturnType));
    
                    // Get the parameters.
                    ParameterInfo[] parameters = method.GetParameters();
    
                    if ((parameters != null) && (parameters.Length != 0))
                    {
                        Console.WriteLine("Parameters of method.");
    
                        // Iterate through parameters and print return type and Name of the method.
                        foreach (ParameterInfo parameter in parameters)
                        {
                            Console.WriteLine(parameter.ParameterType + " " + parameter.Name);
                        }
                    }               
    
                }
            }
    
            // Getting all the interfaces.
            Type[] types = type.GetInterfaces();
            Console.WriteLine();
            Console.WriteLine("Printing Interfaces Information.");
    
            if ((types == null) || (types.Length == 0))
            {
                Console.WriteLine("No Interfaces implemented by the Type.");
            }
            else
            {
                Console.WriteLine(string.Format("Total Number of Interfaces - {0}", types.Length));
    
                // Iterate through all the interfaces. Print Name and IsInterface property.
                foreach (Type obj in types)
                {
                    Console.WriteLine(obj.Name + " " + obj.IsInterface);
                }
            }
        }        
    }

    public interface InterfaceA
    {
        void MethodA();
    }

    /// <summary>
    /// Class showing the usage of different Members.
    /// </summary>
    public class ClassA : InterfaceA
    {
        /// <summary>
        /// Private Field
        /// </summary>
        private int counter = 0;

        /// <summary>
        /// Public Constant
        /// </summary>
        public const string Name = "Dominic";

        /// <summary>
        /// Private Field Array.
        /// </summary>
        private int[] numbers = new int[] { 10, 20, 30, 22, 15 };

        /// <summary>
        /// Property
        /// </summary>
        public int Counter
        {
            get
            {
                return this.counter;
            }

            set
            {
                // Validation done before changing the counter.
                if ((value > 0) && (value != this.counter))
                {
                    this.counter = value;

                    // Notification sent if counter is changed.
                    this.CounterChangeNotifier(this, counter);
                }
            }
        }

        /// <summary>
        /// Public Method.
        /// </summary>
        public void PrintInfo()
        {
            Console.WriteLine("Printing...");
        }

        /// <summary>
        /// Event.
        /// </summary>
        public event EventHandler<int> CounterChangeNotifier;

        /// <summary>
        /// Indexer
        /// </summary>
        /// <param name="index"></param>
        /// <returns></returns>
        public int this[int index]
        {
            get
            {
                return numbers[index];
            }
        }

        /// <summary>
        /// Constructor.
        /// </summary>
        public ClassA()
        {
            this.counter = 0;
        }

        /// <summary>
        /// Constructor with Parameter.
        /// </summary>
        /// <param name="counter"></param>
        public ClassA(int counter)
        {
            this.counter = counter;
        }

        /// <summary>
        /// Destructor.
        /// </summary>
        ~ClassA()
        {
            // Release any resouces here.
        }

        /// <summary>
        /// Private nested class.
        /// </summary>
        private class NestedClass
        {
            // Class definition goes here.
        }

        /// <summary>
        /// Implementing interface method.
        /// </summary>
        public void MethodA()
        {
            // method implementation here.
        }
    }