Reflection and Reflection.Emit in C#


This article has been excerpted from book "The Complete Visual C# Programmer's Guide" from the Authors of C# Corner.

The Reflection.Emit namespace classes can be used to emit Microsoft intermediate language (MSIL) code on the fly so that the generated code can be executed directly. Reflection is also used to obtain information about a class and its members. In other words, reflection is a technology that allows you to examine metadata that describes types and their members. You may have programmatically accessed Component Object Model type libraries before; reflection in .NET is very similar, but it is a lot more powerful and a lot easier to use. When you compile a source file with a .NET compiler, the compiler emits the MSIL of the statements within the source file, along with the metadata that describes the types defined within the file. It is this metadata that the reflection APIs in .NET enable you to examine. The MSIL and metadata are contained in assembly files (typically .dll and .exe files). 

The reflection API in .NET uses the System.Reflection namespace. In this namespace are classes used to help you access structures inherent in a program such as classes, types, fields, structs, enums, members, and methods. For example, you use the Type class to identify the type of the class being reflected, and the FieldInfo class represents the fields of a struct or enum. The MemberInfo class represents the members of the reflected class, and you use the MethodInfo class to represent methods of the reflected class. The ParameterInfo class represents the parameters of a method in the reflected class. 

You can create code at runtime with the System.Reflection.Emit namespace classes, but we must warn you that you must have some knowledge of the MSIL operation codes and the MSIL language to take advantage of the emitting commands. In fact, what you are actually emitting is the MSIL itself behind the scenes. You can use reflection to define an assembly in memory, create a class/module for that assembly, and then create other module members plus new types for that module. You can construct the assembly using emitting. Reflection.Emit is a powerful namespace in which we can dynamically emit transient and persisting assemblies at runtime. Reflection.Emit produces a low-level, language-neutral MSIL. Normally, we create an assembly by saving its source code to disk and then compiling that source code. Then we call the methods of classes that we need to use from that assembly, which was compiled on disk. But as you can imagine, this involves extra disk write and read effort! With reflection emit, we can omit this overhead and immediately emit the operation codes directly into memory. Reflection emitting is nothing but writing any assembly code directly within your code and then invoking the resulting code on the fly. 

You should use Reflection.Emit members for the following reasons:

  • You have your own macro languages, compilers, or script compilers in your applications.
  • You want to improve performance of your algorithms by creating assemblies, classes, modules, and new types during runtime.
  • You want to improve performance of late-bound objects. You can emit the code necessary to call bound types directly, and then call through your emitted method. Although you cannot perform calls as speedily as with early binding, you will perform better than late binding.

The System.Reflection.Emit namespace provides the classes necessary for a user to create an .exe file on the fly. Its classes allow a compiler or tool to emit metadata and MSIL. So you can create .exe files on your disk on the fly as if you were running the code, saving it, and calling the compiler to compile the code. Mostly you will need this feature and this namespace for your custom script engines and compilers. 

The Reflection.Emit namespace has many members you can use for emitting. Here are the two most important ones:

  • The AssemblyBuilder class is the starting point for any application that emits code at runtime and has methods for creating dynamic modules.
  • The ModuleBuilder class is used as the starting point for adding types such as classes and structures to a dynamic assembly at runtime.

The ILGenerator.OpCodes class, which generates MSIL instructions, includes all the MSIL operation codes in its fields that you will need (operation codes are a portion of a set of operation descriptions that specifies the operation to be performed or the set of operations in a computer). MSIL is the typeless operation code of the base assembly language for the CLR or intermediate language. When you code any C# code and compile it, it is transformed into MSIL first. Then when you invoke an assembly in MSIL, it is converted and executed in the corresponding machine language. The easiest way to learn MSIL is to disassemble simple codes that you have compiled. You can disassemble any compiled .NET code by using ILDasm.exe (the IL Disassembler), one of the .NET SDK utilities. After you have compiled the code in Listing 21.28 and run it on the console, a new file is generated in your current folder called TestAsm.exe. This .exe file prints the message "Hello World" on the console. 

Listing 21.28: Creating an .exe File on the Fly (ReflectionEmit.cs) 

using System;
using System.Runtime;
using System.Reflection;
using System.Reflection.Emit;

public class class1
{
    public static void Main()
    {
        AppDomain ad = AppDomain.CurrentDomain;
        AssemblyName am = new AssemblyName();
        am.Name = "TestAsm";
        AssemblyBuilder ab = ad.DefineDynamicAssembly(am, AssemblyBuilderAccess.Save);
        ModuleBuilder mb = ab.DefineDynamicModule("testmod", "TestAsm.exe");
        TypeBuilder tb = mb.DefineType("mytype", TypeAttributes.Public);
        MethodBuilder metb = tb.DefineMethod("hi", MethodAttributes.Public |
        MethodAttributes.Static, null, null);
        ab.SetEntryPoint(metb);

        ILGenerator il = metb.GetILGenerator();
        il.EmitWriteLine("Hello World");
        il.Emit(OpCodes.Ret);
        tb.CreateType();
        ab.Save("TestAsm.exe");
    }
}

Try executing TestAsm.exe, and see whether it works as you expect. Indeed, we can accomplish anything by emitting operation codes that we can do with normal C# code, since they both produce corresponding MSIL in the end. Listing 21.29 is a more sophisticated example that shows how to emit an assembly that contains a method to calculate a factorial on the fly. 

Listing 21.29: Calculating Factorial by Emitting Operation Codes (emitfactorial.cs) 

using System;
using System.Reflection;
using System.Reflection.Emit;
using System.IO;
using System.Threading;
using System.Diagnostics;

// declare the interface
public interface IFactorial
{
    int myfactorial();
}

public class SampleFactorialFromEmission
{
    // emit the assembly using op codes
    private Assembly EmitAssembly(int theValue)
    {
        // create assembly name
        AssemblyName assemblyName = new AssemblyName();
        assemblyName.Name = "FactorialAssembly";

        // create assembly with one module
        AssemblyBuilder newAssembly = Thread.GetDomain().DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
        ModuleBuilder newModule = newAssembly.DefineDynamicModule("MFactorial");

        // define a public class named "CFactorial" in the assembly
        TypeBuilder myType = newModule.DefineType("CFactorial", TypeAttributes.Public);

        // Mark the class as implementing IFactorial.
        myType.AddInterfaceImplementation(typeof(IFactorial));

        // define myfactorial method by passing an array that defines
        // the types of the parameters, the type of the return type,
        // the name of the method, and the method attributes.

        Type[] paramTypes = new Type[0];
        Type returnType = typeof(Int32);
        MethodBuilder simpleMethod = myType.DefineMethod("myfactorial", MethodAttributes.Public |MethodAttributes.Virtual, returnType,        paramTypes);

        // obtain an ILGenerator to emit the IL
        ILGenerator generator = simpleMethod.GetILGenerator();

        // Ldc_I4 pushes a supplied value of type int32
        // onto the evaluation stack as an int32.
        // push 1 onto the evaluation stack.
        // foreach i less than theValue,
        // push i onto the stack as a constant
        // multiply the two values at the top of the stack.
        // The result multiplication is pushed onto the evaluation
        // stack.
        generator.Emit(OpCodes.Ldc_I4, 1);

        for (Int32 i = 1; i <= theValue; ++i)
        {
            generator.Emit(OpCodes.Ldc_I4, i);
            generator.Emit(OpCodes.Mul);
        }

        // emit the return value on the top of the evaluation stack.
        // Ret returns from method, possibly returning a value.

        generator.Emit(OpCodes.Ret);

        // encapsulate information about the method and
        // provide access to the method metadata
        MethodInfo factorialInfo =typeof(IFactorial).GetMethod("myfactorial");

        // specify the method implementation.
        // pass in the MethodBuilder that was returned
        // by calling DefineMethod and the methodInfo just created
        myType.DefineMethodOverride(simpleMethod, factorialInfo);

        // create the type and return new on-the-fly assembly
        myType.CreateType();
        return newAssembly;
    }

    // check if the interface is null, generate assembly
    // otherwise it is already there, where it is to be...
    public double DoFactorial(int theValue)
    {
        if (thesample == null)
        {
            GenerateCode(theValue);
        }

        // call the method through the interface
        return (thesample.myfactorial());
    }

    // emit the assembly, create an instance and
    // get the interface IFactorial
    public void GenerateCode(int theValue)
    {
        Assembly theAssembly = EmitAssembly(theValue);
        thesample = (IFactorial)theAssembly.CreateInstance("CFactorial");
    }

    // private member data
    IFactorial thesample = null;
}

class Class1
{
    [STAThread]
    static void Main(string[] args)
    {
        Int32 aValue = 5;
        SampleFactorialFromEmission t = new SampleFactorialFromEmission();
        double result = t.DoFactorial(aValue);
        Console.WriteLine("Factorial of " + aValue + " is " + result);
    }
}

Conclusion

Hope this article would have helped you in understanding the Reflection and Reflection.Emit in C#. See other articles on the website on .NET and C#.

visual C-sharp.jpg
The Complete Visual C# Programmer's Guide covers most of the major components that make up C# and the .net environment. The book is geared toward the intermediate programmer, but contains enough material to satisfy the advanced developer.

Up Next
    Ebook Download
    View all
    Learn
    View all