Other Posts in Reflection

  1. Using Reflection to get Assembly Information in C#
  2. Overridding a Property With Reflection.Emit
  3. Shallow Copy of an Object Using Reflection
  4. Dynamically Parsing a String to Any Type When You Don't Know The Type
  5. Reflection.Emit the Simple Way

Reflection.Emit the Simple Way

11/10/2010

I haven't posted anything in a while for a couple of reasons. First, I'm working on two web projects (one being a redesign of my site here, the other a media oriented site) and a code automation project (on top of that I have about 10 other projects in the design phase, but waiting before I take them on). Secondly, I've apparently angered someone out there as I've been dealing with getting hundreds of spam messages daily. I may just turn off comments to fix that issue. And the last thing keeping me from posting is the fact that I've been working on this bit of code that I'm going to talk about in this post.

I've said it before and I'll say it again, I'm odd. I like reinventing the wheel, working in obscure/difficult programming languages because I can, etc. Basically if I hear that it's difficult, I'm more interested in doing it. One thing that has been popping up lately in some of my discussions with people is dynamic code generation (IL generation). Mainly the discussion has revolved around how it's too difficult currently and that it would be much simpler if you could use the C# compiler and just concat some strings together. Instead they were left using Reflection.Emit, which is neither easy nor nice to debug. Well once I pointed out that you could use the C# compiler using the CodeDOM (CSharpCodeProvider, etc.), the discussion died off. However, I remained focused on creating a framework around Reflection.Emit to make things easier (mainly because someone said it was difficult).

For those that don't know, there are two ways to generate code on the fly in .Net (the CodeDOM and Reflection.Emit). Or at least those are the only two that I'm aware of. Each has their advantages and disadvantages:

  • Reflection.Emit generation is a bit faster as you're spitting out the IL code yourself while the CodeDOM uses csc.exe to compile C# code (or you can use the VB compiler, etc.)
  • CodeDOM is simpler since you're able to debug it easily and you're writing code directly.
  • Reflection.Emit can actually save you on memory, potentially, depending on how you set it up because you can simply add a class to a preexisting assembly. The CodeDOM on the other hand generates a brand new assembly each time and thus needs to be loaded (and thus can't be unloaded while the app is running).
  • Reflection.Emit also has the ability to generate new methods for existing classes (using dynamic methods). But to be honest, subclassing and using the CodeDOM would give you about the same effect.
Basically what it comes down to is if you're creating a proxy at run time, you probably want Reflection.Emit (think ORMs, etc. where you need to generate potentially new proxies each time the app is run due to changes in the underlying code. But note that if you don't mind waiting on the compiler at startup, or you cache the assembly the CodeDOM should be fine for this as well). If you're generating a whole slew of classes or snippets in some sort of code automation process, use CodeDOM and some templates. But really it just depends on the situation as to which you should use.
 
Anyway, I use Reflection.Emit in my ORM and AOP libraries (although I'm probably going to add a CodeDOM option to the AOP library), so I figured why not create something to ease the burden. With the new classes that I've added to my utility library, I can do something like the following:
   1: Utilities.Reflection.Emit.Assembly TempAssembly = new Utilities.Reflection.Emit.Assembly("TestAssembly", @"C:\Test\");
   2: {
   3:     TypeBuilder Builder = TempAssembly.CreateType("Test.A");
   4:     {
   5:         FieldBuilder Field = Builder.CreateField("Field1", typeof(int));
   6:         FieldBuilder Field2 = Builder.CreateField("Field2", typeof(int));
   7:  
   8:         IMethodBuilder Constructor = Builder.CreateConstructor();
   9:         {
  10:             Constructor.Assign(Field, 19);
  11:             Constructor.Assign(Field2, Field);
  12:             Constructor.Return();
  13:         }
  14:  
  15:         IMethodBuilder Method = Builder.CreateMethod("Method1",
  16:             ReturnType: typeof(List<string>));
  17:         {
  18:             IVariable ReturnObj = Method.NewObj(typeof(List<string>).GetConstructor(Type.EmptyTypes), new List<IVariable>());
  19:             List<IVariable> Parameters = new List<IVariable>();
  20:             IVariable Val1=Method.CreateLocal("Val1",typeof(int));
  21:             Val1.Assign(Method,0);
  22:             Utilities.Reflection.Emit.Commands.While While=Method.While(Utilities.Reflection.Emit.Enums.Comparison.NotEqual, Method.CreateConstant(3), Val1);
  23:             {
  24:                 Parameters = new List<IVariable>();
  25:                 Parameters.Add(Method.CreateConstant("Test"));
  26:                 Method.Call(ReturnObj, typeof(List<string>).GetMethod("Add"), Parameters);
  27:                 Val1.Assign(Method, 3);
  28:             }
  29:             While.EndWhile();
  30:             Method.Return(ReturnObj);
  31:         }
  32:  
  33:         IMethodBuilder Method2 = Builder.CreateMethod("Method2", ReturnType: typeof(List<string>));
  34:         {
  35:             IVariable ReturnVal=Method2.Call(Method2.Parameters[0], ((MethodBuilder)Method).Builder, new List<IVariable>());
  36:             Method2.Return(ReturnVal);
  37:         }
  38:  
  39:         IPropertyBuilder Property = Builder.CreateDefaultProperty("Property1", typeof(Dictionary<string,string>));
  40:     }
  41:  
  42:     EnumBuilder Enum = TempAssembly.CreateEnum("Test.EnumTest", typeof(Int32));
  43:     {
  44:         Enum.AddLiteral("Entry1", 1);
  45:         Enum.AddLiteral("Entry2", 2);
  46:         Enum.AddLiteral("Entry3", 3);
  47:     }
  48: }
  49: TempAssembly.Create();
The code above creates an assembly and then a class (A, in the TestAssembly.Test namespace) and an enum (EnumTest in the TestAssembly.Test namespace). The class constains two fields (Field1 and Field2), a constructor, two methods (Method1 and Method2), and a property (Property1). The constructor assigns Field1 and Field2 the value of 19, Method2 simply calls Method1 and returns the result, and Method1 creates a List<string> object, does a while loop that runs once, and inside it adds the value "Test" to the list object. All of that in 49 lines of code (normally it would be quite a bit more).
 
This was great, but I also wanted a way for someone to be able to show what this code was doing to others who may not understand IL (plus help with debugging). The way I did this was by overloading ToString to give the equivalent C# code to what the functions, objects, etc. were doing behind the scenes. So by doing this:
   1: TextBox.Text=TempAssembly.ToString();
Based on the bit of code above, we get the following C# code sent back:
   1: namespace TestAssembly.Test
   2: {
   3:     public enum EnumTest
   4:     {
   5:         Entry1,
   6:         Entry2,
   7:         Entry3
   8:     }
   9: }
  10:  
  11: namespace TestAssembly.Test
  12: {
  13:     public class A
  14:     {
  15:         public A()
  16:         {
  17:             Field1 = 19;
  18:             Field2 = Field1;
  19:         }
  20:  
  21:  
  22:         public virtual List<String> Method1()
  23:         {
  24:             List<String> ObjLocal0;
  25:             ObjLocal0 = new List<String>();
  26:             Int32 Val1;
  27:             Val1 = 0;
  28:             while (3 != Val1)
  29:             {
  30:                 ObjLocal0.Add("Test");
  31:                 Val1 = 3;
  32:             }
  33:             return ObjLocal0;
  34:         }
  35:  
  36:  
  37:         public virtual List<String> Method2()
  38:         {
  39:             List<String> Method1ReturnObject;
  40:             Method1ReturnObject = this.Method1();
  41:             return Method1ReturnObject;
  42:         }
  43:  
  44:  
  45:         public virtual Dictionary<String, String> Property1 { get; set; }
  46:  
  47:         public Int32 Field1;
  48:         public Int32 Field2;
  49:     }
  50: }
Not the most efficient code, but I'm going to work on that a bit. Anyway, I haven't finished yet or I'd go into detail about each class, but you can access what I have now from the repository. I still have to add the various math operations (+, -, *, etc.), bitwise operations (& | etc.), type casting, for loops, and try/catch blocks. I'm not going to deal with ref, out, arrays, etc. for now, just the basics but I think it will help a great deal. Once this is done I'll probably rework HaterAide and my AOP library to use these classes. But for now, take a look, leave feedback, and happy coding.


Comments