Little intro
Reflector is a (great) decompiler. The most obvious use of it is to load an assembly and recreate source code out of the IL it contains. The assembly itself was built from source code, so we have a mini "cycle of life". In a perfect world, the decompiled code and the orginal source code would be exactly the same (at least in the same language). So we can represent this cycle by the figure below.
Now, let's introduce a new actor in this ecosystem. We want the decompiler to producec CodeDom source code that can be used to generate the original source code as shown in the figure below: we want to produce a CodeDom template that will generate that type.
Sample example
Let's illustrate all this with an example. Consider the following User class:
User
public class User { private string name = "Marc"; public String Name { get { return this.name; } set { this.name=value; } } public override string ToString() { return this.name; } }
We compile User and now, we want Reflector to generate a class that uses CodeDom (indeed Refly) to generate back the User class. This is the tricky part. I need to use Refly to generate code that uses Refly, so that would be building a code generator generator. The template for the User class will look like this:
public class UserTemplate { private Refly.CodeDom.ClassDeclaration _type; private Refly.CodeDom.FieldDeclaration _nameField; private Refly.CodeDom.PropertyDeclaration _nameProperty; private Refly.CodeDom.MethodDeclaration _toStringMethod; public UserTemplate(Refly.CodeDom.NamespaceDeclaration ns) { // add User class to generator this._type = ns.AddClass("User"); this.Declare(); } public virtual void Declare() { this.DeclareFields(); this.DeclareMethods(); this.DeclareProperties(); this.DeclareEvents(); this.DeclareInnerClasses(); } public virtual void DeclareFields() { // adding name field this._nameField = this._type.AddField(typeof(String), "name"); } public virtual void DeclareMethods() { this._toStringMethod = this._type.AddMethod("ToString"); this.PopulateToStringMethod(this._toStringMethod); } public virtual void DeclareProperties() { this._nameProperty = this._type.AddProperty(typeof(String), "Name"); this.PopulateNameProperty(this._nameProperty); } ... }
(The above template is still missing a big part: the generation of the statements and the expression) Now that we have a Refly ClassDeclaration, we can feed it to the CodeGenerator class:
ClassDeclaration
CodeGenerator
NamespaceDeclaration ns = new NamespaceDeclaration("RoundRobin"); UserTemplate template = new UserTemplate(ns); CodeGenerator gen =new CodeGenerator(); gen.GenerateCode("./Output",ns);
And the result of the execution of this program will be this piece of code:
namespace RoundRobin { using System; public class User { private string _name; public virtual string Name { } public virtual void ToString() { } } }
Not so bad for a start, we have gotten our User class back but there are still some big "holes" in it....
Page rendered at Friday, August 08, 2008 7:42:03 AM UTC
Disclaimer The opinions expressed herein are my own personal opinions and do not represent my employer's view in anyway.