An Introduction to Reflection in C#

Environment: C#

Introduction

In this article, we will see something about reflection in .NET. First, we will see what the System.Reflection namespace will do for .NET developers. Reflection allows the inspection of metadata in a PE file and late binding (run time) to types and their members. The System.Reflection namespace defines the following types to analyze the module's metadata of an assembly: Assembly, Module, Enum, ParameterInfo, MemberInfo, Type, MethodInfo, ConstructorInfo, FieldInfo, EventInfo, and PropertyInfo.

The System.Type class is the main class for reflection. The System.Type class is an abstract class and that represents a type in the Common Type System (CLR). By using this class, we can find the type name, the types used in a module (an assembly may contain one or more modules) and namespace, and to see whether a given type is a value or a reference type, and so on. It also allows us to query the type's fields, methods, properties, and events by parsing the corresponding metadata tables. FCL's Serialization mechanism uses reflection to determine what fields a type defines. The serialization formatter then can obtain the values of these fields and write them into the byte stream.

Late bindings can be achieved by using reflection. For example, in some applications, we don't know which assembly to load during compile time, so we ask the user to enter the assembly name and type during run time and the application can load assembly. For this purpose, the System.Reflection.Assembly type offers three static methods that allow you to explicitly load an assembly: Load, LoadFrom, and LoadWithPartialName. These methods are something similar to the LoadLibrary Win32 API. As our System.Reflection namespace is going to work with assembly and metadata, let's see something about assembly and metadata.

Assembly and Metadata

An assembly is a logical DLL or EXE, and a manifest is a detailed description (metadata) of an assembly. The .NET compiler produces a portable executable PE file for CLR with the extensions of .exe or .dll. This PE file is mainly comprised of metadata and IL (Intermediate Language). Metadata contains a number of different tables; for example, a type definition table, a filed definition table, a method definition table, and so forth. By parsing these tables, we can get an assembly's types and attributes. The FCL's System.Reflection namespace supports several types to reflect over or parse these metadata tables.

PE (Portable Executable) = Metadata (bunch definition tables) + IL (Microsoft Intermediate Language) + Some other data which are not relevant to this article.

Example: Reflecting Types (Querying Types)

The following code shows how to query a type for its attributes using the System.Type class. Refer to the download project ReflectionQueryTest.zip. The ReflectType(string) method takes type string and queries all attributes for that type. Call this method by sending different types as parameters. To call different Reflection classes, include using System.Reflection;

using System;
using System.Reflection;

namespace ReflectionQueryTest
{

  public class TestBaseClass {}

  public class TestDerivedClass : TestBaseClass {}

  struct TestStruct {}

  interface TestInterface {}

  class TestAttribute : System.Attribute {}

  enum TestEnum {}

  class Class1
  {
    private static void ReflectType(string sTypeName)
    {
      try
      {
        // get the type from the given string
        Type type = Type.GetType(sTypeName);

        Console.WriteLine("Type name: {0}", type.FullName);
        Console.WriteLine("\tHasElementType = {0}",
                          type.HasElementType);
        Console.WriteLine("\tIsAbstract = {0}",
                          type.IsAbstract);
        Console.WriteLine("\tIsAnsiClass = {0}",
                          type.IsAnsiClass);
        Console.WriteLine("\tIsArray = {0}", type.IsArray);
            .
            .
            .

      }
      catch (System.NullReferenceException)
      {
        Console.WriteLine("{0} is not a valid type", sTypeName);
      }
    }

    static void Main(string[] args)
    {
      // Reflect all the attributes for the given type by
      // passing the name of the type
      ReflectType("System.Int32");
      ReflectType("ReflectionQueryTest.TestDerivedClass");
      ReflectType("ReflectionQueryTest.TestStruct");
      ReflectType("ReflectionQueryTest.TestBaseClass");

      ReflectType("ReflectionQueryTest.TestInterface");
      ReflectType("ReflectionQueryTest.TestAttribute");
      ReflectType("ReflectionQueryTest.TestEnum");
    }
  }
}

Example: Parsing Types of an Assembly

In the following example, we will see how to parse the types in an assembly. To do this, follow these steps:

  1. Get the assembly name.
  2. Instantiate the assembly by using the LoadFrom method.
  3. Call the GetTypes method of the Assembly class. This method returns an array of all types of an assembly. The GetValidAssembly method checks whether the user supplied any assembly; if not, it gets the current assembly name. Include using System.Diagnostics; this is to get the current process name.
private static string GetValidAssembly(string[] sAssem)
{
string sAssemName;

  if (0 == sAssem.Length)
  {
    Process pr = Process.GetCurrentProcess();
    sAssemName = pr.ProcessName + ".exe";
  }
  else
{
    sAssemName = sAssem[0];
  }
  return sAssemName;
}

Call LoadFrom to load the given assembly; it's like calling LoadLibrary in the Win32 API. Then, call the GetTypes method of the assembly class, which returns an object (Type array) that contains all the types in the given assembly. See the example project found in ReflectAssembly.zip.

static void Main(string[] args)
{
  string sAssemblyName = GetValidAssembly(args);
  Assembly assem = Assembly.LoadFrom(sAssemblyName);

  Type[] types = assem.GetTypes();

  foreach (Type t in types)
  {
    try
    {
      Console.WriteLine("Type information for:" + t.FullName);
      Console.WriteLine("\tBase class = " + t.BaseType.FullName);
      Console.WriteLine("\tIs Class = " + t.IsClass);
      Console.WriteLine("\tIs Enum = " + t.IsEnum);
      Console.WriteLine("\tAttributes = " + t.Attributes);
    }
    catch (System.NullReferenceException)
    {
      Console.WriteLine("Error msg");
    }
  }

}

Downloads

Download assembly project - 17 Kb
Download query test project - 18 Kb


Comments

  • yy

    Posted by yy on 12/06/2012 03:42am

    Go explore more ...

    Reply
  • Why bother with this?

    Posted by john on 07/02/2012 10:53am

    This impresses me as "Academic BS" and nothing more.

    • Sad, sad little man

      Posted by jonas bieberlake on 10/19/2012 03:17pm

      When this article was published in uh, 2002, this was hot stuff. You're smugly criticizing this article from ten years back and your only success was showing everybody what a tool you are...if that was your sole intent, I commend your herpaderpary.

      Reply
    Reply
  • testing

    Posted by testing on 04/25/2012 10:42pm

    its really healpful

    Reply
  • Have bug when a assemply contain an interface that defined an event

    Posted by Legacy on 09/09/2003 12:00am

    Originally posted by: Le Tan Phu

    It appears that Assembly.Load() doesn't work when my assemply contain an inteface (or class inherit an interface) define an event.
    This is my code:

    public interface IInterface
    {
    void Dosomethings();
    event EventHandler OnChangeStatus;

    }

    I have a class implement that interface:

    public class MyClass: IInterface
    {
    ....
    }

    In my application I use Assembly.Load() to load dll that contain MyClass. So It return null.
    Has anyone else seen this?

    Thanks,
    Le Tan Phu

    Reply
  • Good work keep it up!!!!

    Posted by Legacy on 05/27/2003 12:00am

    Originally posted by: Ranga Wickramadara

    This article helped me a lot in getting the background of Reflection as I was writing an Article on Reflection.Emit

    Reply
  • Good article on Reflection

    Posted by Legacy on 12/09/2002 12:00am

    Originally posted by: Venkatraman Kalyanam

    Nice article on reflection front.
    thanks

    Reply
  • How to "use" reflection

    Posted by Legacy on 10/29/2002 12:00am

    Originally posted by: Alok Govil

    I am new to it.

    Getting information about classes, methods, etc, at run-time is one thing, what do I do with this information beyond outputing it on screen.

    Thanks

    Reply
Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • On-demand Event Event Date: September 10, 2014 Modern mobile applications connect systems-of-engagement (mobile apps) with systems-of-record (traditional IT) to deliver new and innovative business value. But the lifecycle for development of mobile apps is also new and different. Emerging trends in mobile development call for faster delivery of incremental features, coupled with feedback from the users of the app "in the wild." This loop of continuous delivery and continuous feedback is how the best mobile …

  • The explosion in mobile devices and applications has generated a great deal of interest in APIs. Today's businesses are under increased pressure to make it easy to build apps, supply tools to help developers work more quickly, and deploy operational analytics so they can track users, developers, application performance, and more. Apigee Edge provides comprehensive API delivery tools and both operational and business-level analytics in an integrated platform. It is available as on-premise software or through …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds