Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C#

Reflection in .NET - Part I

5.00/5 (9 votes)
27 May 2015CPOL4 min read 20.4K   248  
In this series of articles, we would be discussing about - Reflection in .NET

Preface

In this series of articles, we would be discussing in detail about - Reflection in .NET, and then take a deep dive into different aspects of Reflection in .NET and also cover the various classes in System.Reflection namespace. On our path to understanding Reflection, we would be covering a lot of sample examples (demo programs which I have created) to explain the concept practically. I will be including various techniques using examples (demo programs) which the programmers can use in their applications while implementing Reflection.

Introduction

An Assembly is the minimum unit of deployment. You cannot deploy anything less than an assembly. For the CLR, a type does not exist outside the context of an assembly. Assemblies contains four elements (The assembly Manifest, Type metadata, MSIL and Resources.). Each assembly contains a collection of data that describes how the elements in the assembly relate to each other. For more information on Assemblies, see bottom section – References. In our custom .NET applications, while using Reflection, the Type metadata information will be used.

What is Reflection?

Reflection in .NET allows us to programmatically load the assemblies and obtain information about the types (classes, interface and value types) defined in the assemblies.

Reflection can also be used to dynamically create instance of a type, bind the type to an existing object, or get the type information from and existing object. The .NET framework includes System.Reflection and the System.Type and they together form the reflection API, this API can be used to programmatically obtain information of the loaded assembly.

Reflection also allows you to perform late binding - wherein you load the assembly, access the type, create an instance of the type, invoke the methods of the type (using the method name) all at runtime.

Let’s start with our first demo.

Using Reflection - for Loading a .NET Framework Assembly and Displaying the Types

Below is the complete running code (console application). In the steps below, I will walk you through each line of the code.

C#
using System;
using System.Reflection; // Using the Reflection Assembly.

namespace Reflection_Client_Sample
{
    class Program
    {
        static void Main(string[] args)
        {
            string assemblyPath = @"C:\\Windows\\Microsoft.NET\\Framework\\v4.0.30319\\System.Data.dll";
            Assembly assembly = Assembly.LoadFrom(assemblyPath);

            // Get the complete name of the assembly that is loaded from file using FullName or GetName()
            Console.WriteLine("Assembly Full Name : {0}", assembly.FullName);       

            //Store the types contained in assembly in array
            Type[] assemblyTypes = assembly.GetTypes();

            foreach (Type t in assemblyTypes)
            {
                // Display the full name of type under the loaded assembly.
                Console.WriteLine(t.FullName);                               
            }

            Console.Read();
        }
    }
}

In this console application example - we are loading the .NET assembly (System.Data.dll) and looping through the types contained in this assembly at runtime using the reflection.

First, you specify the reflection namespace using the using directive.

C#
using System.Reflection; // Using the Reflection Assembly.

Inside the Main method (entry point for C# console application), define a string variable to specify the exact location (path) of the assembly. (You can specify any other .NET assembly name with complete path).

C#
string assemblyPath = @"C:\\Windows\\Microsoft.NET\\Framework\\v4.0.30319\\System.Data.dll";

On the next line, the above specified path would be used to load the assembly using LoadFrom(), which accepts a string parameter (i.e., path of the assembly).

C#
Assembly assembly = Assembly.LoadFrom(assemblyPath);

On the next line, we display the full Name (Fully qualified Name of the Assembly with Namespace information, name, version, culture and public key) of the assembly that’s loaded.

C#
// Get the complete name of the assembly that is loaded from file using FullName or GetName()
Console.WriteLine("Assembly Full Name : {0}", assembly.FullName); 

In the next line using the GetTypes() method, we will get all the types from the loaded assembly in a Type[].

C#
//Store the types contained in assembly in array
  Type[] assemblyTypes = assembly.GetTypes();

We will then use foreach to loop through the types and display the FullName of each type on the console screen.

C#
foreach (Type t in assemblyTypes)
    Console.WriteLine(t.FullName);

Image 1

We can further extend this example, to display the methods and public properties contained under each type for this loaded assembly.

Below is the complete running code. I will walk you through foreach loop section of the code.

C#
using System;
using System.Reflection; // Using the Reflection Assembly.

namespace Reflection_Client_Sample
{
  class Program
  {
   static void Main(string[] args)
   {
     string assemblyPath = @"C:\\Windows\\Microsoft.NET\\Framework\\v4.0.30319\\System.Data.dll";
     Assembly assembly = Assembly.LoadFrom(assemblyPath);

     // Get the complete name of the assembly that is loaded from file using FullName or GetName()
     Console.WriteLine("Assembly Full Name : {0}", assembly.FullName);       

     //Store the types contained in assembly in array
     Type[] assemblyTypes = assembly.GetTypes();

     foreach (Type t in assemblyTypes)
       {
         // Display the full name of type under the loaded assembly.
         Console.WriteLine(t.FullName); 
                              
         //Search for the members based on the criteria specified in the BindingsFlags
         MemberInfo[] membersinfo = t.GetMembers
            (BindingFlags.Public | BindingFlags.DeclaredOnly | BindingFlags.Instance);
           foreach (MemberInfo m in membersinfo)
               Console.WriteLine("Member type: {0}, member name: {1}.", m.MemberType, m.Name);
       }

       Console.Read();
    }
  }
}

Inside the foreach loop, we define an array of MemberInfo[]and then using the GetMembers() method of Type class, we get all the member information.

C#
//Search for the members based on the criteria specified in the BindingsFlags
MemberInfo[] membersinfo = t.GetMembers(BindingFlags.Public | 
BindingFlags.DeclaredOnly | BindingFlags.Instance);

Note: Here, I have specified the BindingsFlag – it’s used for specifying the way in which reflection should do search for the Member under each type (in this case, the search should be one - only public member, second – members which are declared in the Type and not inherited from base type and the third search for only instance members, i.e., non-static members).

Not having BindingsFlag will get all the information about the members for that particular type and in most cases, we would need only specify member information, so in such cases bindingFlags criteria would help.

C#
foreach (MemberInfo m in membersinfo)
 Console.WriteLine("Member type: {0}, member name: {1}.", m.MemberType, m.Name);

We then display the member type and the member name under each Type for the loaded assembly.

Image 2

Points of Interest

  1. Learn What Reflection is?
  2. How to load a .NET framework assembly using Reflection
  3. Display the Types from the loaded assembly
  4. Display the members - Properties, Fields and Methods under each Type
  5. Use of BindingFlags

References

In the next article, we will load a custom .NET application Class library DLL and find the type and member information. We will discuss in detail the System.Type.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)