Generating Executable Code or Class Libraries for Custom Class Snippets (C# Script) at Runtime


This Article provides a code Snippet to illustrate generating executable code (classes) at run time using C# compiler. This Sample also includes Code to use Reflection to create instance of a class (from specified namespace) and also to call class methods alongwith parameters.

Compiling C# script at runtime



Features covered in this Article are:

1. Runtime compilation of C# code
2. Reflection

Microsoft.CSharp.CSharpCodeProvider class provides feature to compile any C# code that you (our your user) feeds to the application on-the-fly.

Once the code is compiled its members can be accessed with the help of reflection (another features of .Net) and perform any operation like you do with a normal C# class member.

Start with Visual Studio 2010 Console Application and make your main() method as follows:



using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

// Included for C# script compilation at run time
using Microsoft.CSharp;
using System.CodeDom.Compiler;
using System.Reflection;

namespace HiEverybody
{
  class Program
  {
    static void Main(string[] args)
    {

      #region MAKING 2 EXECUTION BLOCKS

      string block1 =
          @"
          namespace HiEverybody
          {
            public class WelcomeClass
            {
              public void TestMethod(string userMessage)
              {
                MyLibrary myLibrary = new MyLibrary();
                System.Console.WriteLine(""This Code block was compiled because you entered Option : 1"");

                myLibrary.MyMethod1(""'"" + userMessage + ""' This message was entered by you"");
                myLibrary.MyMethod2(""'Welcome World!' This is System generated message"");

                System.Console.ReadKey();
              }
            }

            public class MyLibrary
            {
              public void MyMethod1(string message)
              {
                System.Console.WriteLine(""(in MyMethod1) : "" + message);
              }

              public void MyMethod2(string message)
              {
                System.Console.WriteLine(""(in MyMethod2) : "" + message);
              }
            }
          }";

      string block2 =
          @"
          namespace HiEverybody
          {
            public class WelcomeClass
            {
              public void TestMethod(string userMessage)
              {
                System.Console.WriteLine(""This Code block was compiled because you entered Option : 2"");
                System.Console.WriteLine(""(in TestMethod) : '"" + userMessage + ""' This message was entered by you"");
                System.Console.ReadKey();
              }
            }
          }";

      #endregion

      #region USER INPUT

      Console.WriteLine("Enter the option (1 or 2):");
      String option = Console.ReadLine();

      if (null == option)
      {
        Console.WriteLine("!! BLANK !! Wrong Option?");
        Console.ReadKey();
        return;
      }

      if (!(option == "1" || option == "2"))
      {
        Console.WriteLine("!! OTHER THEN 1 and 2 !! Wrong Option?");
        Console.ReadKey();
        return;
      }

      #endregion

      #region C# COMPILER - Perform runtime compilation

      // setting the compiler version
      Dictionary<string, string> providerOptions = new Dictionary<string, string> { { "CompilerVersion", "v3.5" } };

      // getting the C# compiler provider
      CSharpCodeProvider provider = new CSharpCodeProvider(providerOptions);

      // setting compilation parameters
      CompilerParameters compilerParams = new CompilerParameters
      {
        // output will be generated in memory
        GenerateInMemory = true,
        // output will be of type "executable"
        GenerateExecutable = false
        // there are also other parameters for different types of initial settings
      };

      // start with a CompilerResults reference as null (will be instentiated as per the option selected)
      CompilerResults compilerResults = null;

      // compiling as per the option
      object[] myParameters = null;
      
      // compile as per requirement
      if (option == "1")
      {
        compilerResults = provider.CompileAssemblyFromSource(compilerParams, block1);
        myParameters = new object[] { "Its too cold today!!..." }; // this is your parameter for method
      }

      if (option == "2")
      {
        compilerResults = provider.CompileAssemblyFromSource(compilerParams, block2);
        myParameters = new object[] { "Its too hot today!!..." }; // this is your parameter for method

      }

      // see if any error generated during compilation
      if (compilerResults.Errors.Count != 0)
        throw new Exception("Run time compilation Failed!");

      #endregion

      // we are here that means Runtime compilation of C# code was successful

      #region REFLECTION - Executing desired method

      // create class object
      var myClassObject = compilerResults.CompiledAssembly.CreateInstance("HiEverybody.WelcomeClass");

      // retrieve the required method name to execute
      MethodInfo methodInfo = myClassObject.GetType().GetMethod("TestMethod");

      // invoking the desired method
      methodInfo.Invoke(myClassObject, myParameters);

      #endregion

    }
  }
}


Once you are done with code you can test it with F5 (Run).

Hope this Code shippet would help some of the developers writing dynamic codes and compiling them as per runtime requirement.

Thanks


Comments

Guest Author: vijay20 Sep 2012

great!!!



  • Do not include your name, "with regards" etc in the comment. Write detailed comment, relevant to the topic.
  • No HTML formatting and links to other web sites are allowed.
  • This is a strictly moderated site. Absolutely no spam allowed.
  • Name:
    Email: