Including Common Intermediate Language to your .Net designer toolbox – generating CIL

An interesting technique is called generative programming, “is a software engineering paradigm based on modeling software system families such that, given a particular requirements specification, a highly customized and optimized intermediate or end-product can be automatically manufactured on demand from elementary, reusable implementation components by means of configuration knowledge” as stated by Krzysztof Czarnecki and Ulrich Eisenecker in “Generative Programming: Methods, Tools, and Applications”

 

See more at:

 

Components and Generative Programming

https://www.prakinf.tu-ilmenau.de/~czarn/esec99/

 

Generative and Component-Based Software Engineering

https://www.prakinf.tu-ilmenau.de/~czarn/generate/engl.html

 

Generative Programming - Methods, Tools, and Applications

https://www.generative-programming.org/

 

 

Heavy use of analysis techniques like domain engineering, conceptual modeling, commonality and variability analysis, are applied to help with software designs and implementations that are better aligned to the application logic in context. Looks like a very compelling paradigm.

 

Current implementation mechanisms include among others, C++ templates, generic programming and also the generators technique (programs that create programs).

 

Works with C++ templates are:

 

Reflective Metaprogramming in C++ by Daveed Vandevoorde

https://anubis.dkuug.dk/jtc1/sc22/wg21/docs/papers/2003/n1471.pdf

 

Generative Matrix Computation Library

https://www.prakinf.tu-ilmenau.de/~czarn/gmcl/

 

 

Another mechanism for implementing generative programming concepts is using the .Net System.Reflection.Emit namespace that allow a compiler or tool to emit metadata and Microsoft Common Intermediate Language (CIL) at run time and optionally generate a portable executable file on disk.

 

Let’s programmatically generate the same simplistic program we created at:

Including Common Intermediate Language to your .Net designer toolbox - the beginning

https://blogs.msdn.com/marcod/archive/2004/02/20/76836.aspx

 

Let’s create a console application with C#, create a text file with extension .cs

 

A starting point is an assembly name:

 

AssemblyName assemblyName=new AssemblyName();

assemblyName.Name="unogen";

 

Then we need an AppDomain object:

 

AppDomain appdomain=Thread.GetDomain();

 

It helps us to create our dynamic assembly:

 

AssemblyBuilder assembler =appdomain.DefineDynamicAssembly(assemblyName,AssemblyBuilderAccess.RunAndSave);

 

A module is created next:

 

ModuleBuilder moduler=assembler.DefineDynamicModule("unogen.exe");

 

With a global method:

 

MethodBuilder functor

=moduler.DefineGlobalMethod("start",MethodAttributes.Static|MethodAttributes.Public,null,null);

 

The CIL instructions inside the method are create with a ILGenerator:

 

ILGenerator emitter=functor.GetILGenerator();

emitter.EmitWriteLine("here uno is executing");

emitter.Emit(OpCodes.Ret);

moduler.CreateGlobalFunctions();

 

Lastly, we define our entry point and save the assembly to disk:

 

assembler.SetEntryPoint(functor);

assembler.Save("unogen.exe");

 

That’s it, the complete listing is:

 

using System;

using System.Threading;

using System.Reflection;

using System.Reflection.Emit;

class exe

{

      static void Main(string[] args)

      {

            AppDomain appdomain=Thread.GetDomain();

            AssemblyName assemblyName=new AssemblyName();

            assemblyName.Name="unogen";

            AssemblyBuilder assembler=appdomain.DefineDynamicAssembly(assemblyName,AssemblyBuilderAccess.RunAndSave);

            ModuleBuilder moduler=assembler.DefineDynamicModule("unogen.exe");

            MethodBuilder functor=moduler.DefineGlobalMethod("start",MethodAttributes.Static|MethodAttributes.Public,null,null);

            ILGenerator emitter=functor.GetILGenerator();

            emitter.EmitWriteLine("here uno is executing");

            emitter.Emit(OpCodes.Ret);

            moduler.CreateGlobalFunctions();

            assembler.SetEntryPoint(functor);

            assembler.Save("unogen.exe");

      }

}

 

Compile and run to see the Reflection.Emit magic and there should be a file named unogen.exe that execute as expected.