{"id":695,"date":"2009-10-02T00:00:00","date_gmt":"2009-10-02T00:00:00","guid":{"rendered":"https:\/\/test.simple-talk.com\/uncategorized\/net-reflector-meets-the-codedom\/"},"modified":"2021-05-17T18:36:39","modified_gmt":"2021-05-17T18:36:39","slug":"net-reflector-meets-the-codedom","status":"publish","type":"post","link":"https:\/\/www.red-gate.com\/simple-talk\/development\/dotnet-development\/net-reflector-meets-the-codedom\/","title":{"rendered":".NET Reflector meets the CodeDom"},"content":{"rendered":"<div id=\"pretty\">\n<h2>Introduction<\/h2>\n<p class=\"START\">Reflector does a wonderful job translating an Assembly into higher level languages.&#160; When you select &#8220;Disassemble&#8221;, this is what is happening in the background.&#160; The Metadata in the Assembly in translated to an appropriate representation in C# or VB or whatever languages you have installed.&#160; Reflector takes things a step further than this marvel,&#160; providing the mechanisms needed to add virtually any functionality that you find missing.&#160; This includes creating your own &#8220;language&#8221; to disassemble to.<\/p>\n<p>For our purposes, we will define a &#8220;Reflector Language&#8221; as a piece of code that converts an object from the Reflector object model into useful text.&#160;&#160; For C#, VB.Net, etc, these objects are translated into the textual representation that will produce the same metadata that was converted.<\/p>\n<p>Here we will step through creating a &#8220;Reflector Language&#8221; that will result in the CodeDom code needed to generate the code that was parsed.&#160;&#160; <\/p>\n<h2>Anatomy of a Reflector Language<\/h2>\n<p>When creating a language from scratch you have to create the lexical analyzer and the parser.&#160;&#160; The lexical analyzer will separate a character string into valid tokens for your language.&#160; The parser assembles these tokens into something meaningful, based on the grammar for your language.&#160; <\/p>\n<p>We won&#8217;t have to worry about most of this.&#160; Reflector will present us with meaningful objects from the <b>Reflector.CodeModel<\/b> namespace based on the meta data from the Assembly being parsed.&#160; To build our &#8220;language&#8221;, we need to write code explaining what to do when&#160; each of these objects are encountered.&#160;&#160; We don&#8217;t really care about how Reflector determined that we have a <b>ConditionStatement<\/b>,; we simply focus on what our language needs to do when a <b>ConditionStatement<\/b> is found.<\/p>\n<p>There are a handful of objects that you will need to implement in order to define a language.&#160; Remember that an Add-in is just a class library.&#160;&#160; In our class library, we must provide an object implementing the <b>Reflector.IPackage<\/b> interface, the <b>Reflector.CodeModel.ILanguage<\/b> Interface, and the <b>Reflector.CodeModel.ILanguageWriter<\/b> interface.&#160;&#160; By themselves none of these are too difficult to implement.<\/p>\n<p>The <b>IPackage<\/b> object will provide the details needed to register our language with Reflector.&#160;&#160; Specifically, we need to provide a Load and Unload method that will register our language with the <b>LanguageManagerService<\/b><\/p>\n<pre class=\"lang:c# theme:vs2012\">public class CodeDomLanguagePackage : IPackage\n&#160;&#160;&#160; {\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; \/\/ Fields\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; private CodeDomLanguage language;\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; private ILanguageManager languageManager;\n&#160;\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; \/\/ Methods\n&#160;\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; #region IPackage Members\n&#160;\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; public void Load(IServiceProvider serviceProvider)\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; {\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; language = new CodeDomLanguage();\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; languageManager = (ILanguageManager)\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; serviceProvider.GetService(typeof (ILanguageManager));\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; languageManager.RegisterLanguage(language);\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; } } \n&#160;\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; public void Unload()\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; {\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; languageManager.UnregisterLanguage(language);\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; } \n&#160;\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; #endregion\n&#160;&#160;&#160; }\n<\/pre>\n<p>The <b>ILanguage<\/b> object has one method of interest.&#160; <b>GetWriter<\/b> will be called by Reflector as needed and&#160; allow us to associate an <b>IFormatter <\/b>and an <b>ILanguageWriterConfiguration<\/b> to our writer.<\/p>\n<pre class=\"lang:c# theme:vs2012\">public ILanguageWriter GetWriter(IFormatter formatter,\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160;&#160;ILanguageWriterConfiguration configuration)\n{\n&#160;&#160;&#160; return new CodeDomLanguageWriter\n&#160;&#160;&#160;&#160;&#160;&#160; (formatter, configuration);\n}\n<\/pre>\n<p>The <b>ILanguageWriter<\/b> provides various methods that will be called by Reflector when different types of code are to be processed.<\/p>\n<table class=\"MsoNormalTable\">\n<tbody>\n<tr>\n<td>\n<p class=\"TableContents bold\">WriteAssembly<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"TableContents\">Called when you disassemble an Assembly<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p class=\"TableContents bold\">WriteAssemblyReference<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"TableContents\">Called when you disassemble the Assembly references<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p class=\"TableContents bold\">WriteEventDeclaration<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"TableContents\">Called when you disassemble an Event Declaration<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p class=\"TableContents bold\">WriteExpression<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"TableContents\">Called when you disassemble an Expression<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p class=\"TableContents bold\">WriteFieldDeclaration<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"TableContents\">Called when you disassemble a Field declaration <\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p class=\"TableContents bold\">WriteMethodDeclaration<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"TableContents\">Called when you disassemble a Method declaration<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p class=\"TableContents bold\">WriteModule<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"TableContents\">Called when you disassemble a Module<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p class=\"TableContents bold\">WriteModuleReference<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"TableContents\">Called when you disassemble an embedded reference at a module level<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p class=\"TableContents bold\">WriteNamespace<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"TableContents\">Called when you disassemble a Namespace<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p class=\"TableContents bold\">WritePropertyDeclaration<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"TableContents\">Called when you disassemble a Property Declaration<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p class=\"TableContents bold\">WriteResource<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"TableContents\">Called when you disassemble an embedded Resource<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p class=\"TableContents bold\">WriteStatement<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"TableContents\">Called when you disassemble a Statement in isolation<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p class=\"TableContents bold\">WriteTypeDeclaration<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"TableContents\">Called when you disassemble a Type Declaration<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p class=\"MsoNormal\">These various methods allow you to customize what gets displayed in the Disassembler window as the user clicks on the various levels in the TreeView.&#160;&#160; When you leave a blank implementation then nothing will be displayed at that level in the TreeView.&#160;&#160; At a minimum, you should display an informative message about what is being viewed.&#160;&#160; For example, this may be all that you need for a minimal implementation of VisitNameSpace<\/p>\n<pre class=\"lang:c# theme:vs2012\">public void WriteNamespace(INamespace value)\n{\n&#160;&#160;&#160; formatter.Write (\"Visiting the \" + value.Name + \" namespace\");\n&#160;&#160;&#160; formatter.WriteLine ();\n&#160;&#160;&#160; formatter.Write(\"It has \" + value.Types.Count + \" types\");\n&#160;&#160;&#160; formatter.WriteLine();\n&#160;\n}\n<\/pre>\n<p>As in life, the devil is in the details.&#160;&#160; Providing the details for how to process the various language structures is where the complexities come in.<\/p>\n<h2>Languages are Recursive<\/h2>\n<p>Language components are defined in terms of themselves.&#160;&#160; This is true for natural languages like English, French, and Spanish.&#160;&#160; It is also true for programming languages like C#, VB, and Java. This makes their definitions recursive.&#160;&#160; <\/p>\n<p>A simple example in English is illustrated through the following series of phrases:<\/p>\n<ul>\n<li>My car  <\/li>\n<li>My&#160; father&#8217;s car  <\/li>\n<li>My&#160; father&#8217;s brother&#8217;s car  <\/li>\n<li>My father&#8217;s brother&#8217;s wife&#8217;s car etc. <\/li>\n<\/ul>\n<p>As prevalent as this is with Natural Languages, it is even more widespread with computer programming languages.&#160;&#160; There are two main base Interfaces in the <b>Reflector.CodeModel<\/b> namespace, <b>IStatement <\/b>and <b>IExpression<\/b>.&#160;&#160; These show up widely in recursive definitions.&#160;&#160; For example, an <b>IBinaryExpression<\/b> is an <b>IExpression<\/b> with two properties, Left and Right.&#160;&#160; Both of these properties, are of type <b>IExpression<\/b> and can implement any interface derived from <b>IExpression<\/b>, including <b>IBinaryExpression<\/b>.&#160; This makes the definition recursive.&#160;&#160;&#160; This also means that while parsing nearly every language structure, you may also encounter nearly any language structure.<\/p>\n<p>The Visitor pattern makes it easier to deal with some of the complexities that can arise from the recursive nature of the language definitions.&#160;&#160; Instead of having to keep in mind every possibility when we encounter an <b>IExpression<\/b>, we can defer that responsibility to a more generalized <b>VisitExpression<\/b> and let it figure out the specific derived interface the object being visited implements.<\/p>\n<p>Instead of adding code to support the various types that you can encounter in each type, we can write the code for each type in its own method and then call the Visitor to &#8220;visit&#8221; every possibility for the derived types.&#160;&#160;&#160; <\/p>\n<h2>A Sample Visitor<\/h2>\n<p>The <b>VisitBinaryExpression<\/b> may have an implementation similar to this:<\/p>\n<pre class=\"lang:c# theme:vs2012\">&#160;\npublic override void VisitBinaryExpression(IBinaryExpression value)\n{\n&#160;&#160;&#160; if (value != null)\n&#160;&#160;&#160; {\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; System.CodeDom.CodeBinaryOperatorExpression exp =\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; new System.CodeDom.CodeBinaryOperatorExpression();\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; string name = \"binaryExpression\";\/\/ +value.ToString();\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; formatter.Write(\"System.CodeDom.CodeBinaryOperatorExpression \"\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; + name +\" = new System.CodeDom.CodeBinaryOperatorExpression();\");\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; formatter.Write (MethodTarget.BuildCodeString(name));\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; formatter.WriteLine();\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; codeStack.Push(new CodeStackItem(name, \"Left\", false));\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; VisitExpression(value.Left);\n&#160;&#160;&#160;&#160;&#160; &#160;&#160;codeStack.Pop();\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; formatter.WriteLine ();\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; switch (value.Operator)\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; {\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; . . .\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; }\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; formatter.WriteLine();\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; codeStack.Push(new CodeStackItem(name, \"Right\", false));\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; VisitExpression(value.Right);\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; codeStack.Pop();\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; formatter.WriteLine();\n&#160;&#160;&#160; }\n}\n&#160;\n<\/pre>\n<p>&#160;Inside the switch statement, we handle the various values in the <b>BinaryOperator<\/b> enumeration.&#160;&#160; The key things to note here are the two calls to <b>VisitExpression<\/b>, the use of <b>codeStack<\/b>, and the call to <b>MethodTarget<\/b> <b>BuildCodeString<\/b>.&#160;&#160; The code stack allows us track context for what we are visiting.&#160;&#160; The <b>CodeStackItem<\/b> includes the name of the object that triggered&#160; the visitation (the <b>ActiveBlock<\/b>), the name of the property that we are visiting (the <b>ActiveCollection<\/b>), and an indicator for whether or not this is to be a collection or a single item (<b>IsCollection<\/b>).<\/p>\n<p><b>VisitExpression<\/b>, is a long but simple method blindly calling every visitor derived from <b>IExpression<\/b> looking for matches:<\/p>\n<pre class=\"lang:c# theme:vs2012\">public void VisitExpression (IExpression value)\n{\n&#160;&#160;&#160; if (value != null)\n&#160;&#160;&#160; {\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; VisitAddressOfExpression(value as IAddressOfExpression);\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; VisitAddressOutExpression(value as IAddressOutExpression);\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; VisitAddressReferenceExpression(value as\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &#160;IAddressReferenceExpression);\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; VisitAnonymousMethodExpression(value as IAnonymousMethodExpression);\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; VisitArgumentListExpression(value as IArgumentListExpression);\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; VisitArgumentReferenceExpression(value as\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &#160;IArgumentReferenceExpression);\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; VisitArrayCreateExpression(value as IArrayCreateExpression);\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; VisitArrayIndexerExpression(value as IArrayIndexerExpression);\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; VisitAssignExpression(value as IAssignExpression);\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; VisitBaseReferenceExpression(value as IBaseReferenceExpression);\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; VisitBinaryExpression(value as IBinaryExpression);\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; VisitBlockExpression(value as IBlockExpression);\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; VisitCanCastExpression(value as ICanCastExpression);\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; VisitCastExpression(value as ICastExpression);\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; VisitConditionExpression(value as IConditionExpression);\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; VisitDelegateCreateExpression(value as IDelegateCreateExpression);\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; VisitDelegateInvokeExpression(value as IDelegateInvokeExpression);\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; VisitEventReferenceExpression(value as IEventReferenceExpression);\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; VisitExpressionCollection(value as IExpressionCollection);\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; . . . .\n&#160;&#160;&#160; }\n}\n&#160;\n<\/pre>\n<p>If value is not of the correct type, the as operator will return null.&#160;&#160; Each method will verify that null was not passed in adding marginal extra complexity to each method, but dramatically lowering the complexity of the <b>VisitExpression<\/b>.&#160;&#160;&#160; We use&#160; a similar method for <b>VisitStatement<\/b> and <b>VisitType<\/b>.<\/p>\n<p><b>MethodTarget<\/b> is a property of type <b>CodeStackItem<\/b> that standardizes accessing the top item&#160; in the <b>CodeStack.<\/b><\/p>\n<pre class=\"lang:c# theme:vs2012\">public CodeStackItem&#160; MethodTarget\n{\n&#160;&#160;&#160; get\n&#160;&#160;&#160; {\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; CodeStackItem returnValue = null;\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; if (codeStack.Count &gt; 0)\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; {\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; returnValue = codeStack.Peek();\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; }\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; else\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; throw new System.Exception(\"No code items in the stack\");\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; return returnValue;\n&#160;&#160;&#160; }\n}\n&#160;\n<\/pre>\n<p>The <b>BuildCodeString<\/b> method from the <b>CodeStackItem<\/b> class handles the interpretation of a <b>CodeStackItem<\/b> and produces a string suitable for adding to our code:<\/p>\n<pre class=\"lang:c# theme:vs2012\">public string BuildCodeString(string value)\n{\n&#160;&#160; &#160;string returnValue = \"\";\n&#160;&#160;&#160; if (isCollection)\n&#160;&#160;&#160; {\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; returnValue = ActiveBlock + \".\" + ActiveCollection + \".Add(\"\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; + value + \");\";\n&#160;&#160;&#160; }\n&#160;&#160;&#160; else\n&#160;&#160;&#160; {\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; returnValue = activeBlock + \".\" + ActiveCollection\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; + \" = \" + value + \";\";\n&#160;&#160;&#160; }\n&#160;&#160;&#160; return returnValue;\n}\n&#160;\n<\/pre>\n<h2>Pulling it All Together<\/h2>\n<p>The visitor pattern makes our code easier to structure.&#160;&#160; It also allows us to have a nice structure to produce a usable language even as we are adding support for more features.&#160;&#160; We can provide visitor methods for features that we have not yet implemented that will simply announce that a given feature is not yet supported and then have a convenient place to add the missing functionality as we are ready.&#160;&#160;&#160; When you get started writing a language, many of the visitor methods may be as simple as this:<\/p>\n<pre class=\"lang:c# theme:vs2012\">public override void VisitAddressDereferenceExpression\n&#160;&#160;&#160;&#160;&#160; (IAddressDereferenceExpression value)\n{\n&#160;&#160;&#160; if (value != null)\n&#160;&#160;&#160; {\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; WriteUnsupported(value);\n&#160;&#160;&#160; }\n}\nThe WriteUnsupported method could be similar to this.\n&#160;\nprivate void WriteUnsupported(IExpression value)\n{\n&#160;&#160;&#160; if (value != null)\n&#160;&#160;&#160; {\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; formatter.WriteLiteral(\"\/\/ Unsupported expression \"\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; + value.GetType().Name + \":\");\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; formatter.WriteLine();\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; formatter.WriteLiteral(\"\/\/\" + value);\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; formatter.WriteLine();\n&#160;&#160;&#160; }\n}\n<\/pre>\n<p>Now you are free to implement the language features that are important to you.<\/p>\n<p>One important language feature to implement is a property declaration.&#160; Our property declaration visitor may look similar to this:<\/p>\n<\/p>\n<pre class=\"lang:c# theme:vs2012\">public override void VisitPropertyDeclaration(IPropertyDeclaration value)  \n{\n&#160;&#160;&#160; formatter.WriteKeyword(\"public void\");\n&#160;&#160;&#160; WriteWhitespace();\n&#160;&#160;&#160; formatter.WriteDeclaration(\"CreateProperty\" + value.Name+\"()\");\n&#160;&#160;&#160; formatter.WriteLine();\n&#160; &#160;&#160;using (new IndentedCodeBlock(formatter))\n&#160;&#160;&#160; {\n&#160;&#160;&#160;&#160;&#160;&#160; formatter.Write(\"System.CodeDom.CodeMemberProperty \"\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; + value.Name\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; + \" = new System.CodeDom.CodeMemberProperty();\");\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; codeStack.Push(new CodeStackItem(value.Name, \"Type\", false));\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; VisitType(value.PropertyType);\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; codeStack.Pop();\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; formatter.WriteLine();\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; formatter.Write(value.Name + \".Name = \\\"\" + value.Name + \"\\\";\");\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; formatter.WriteLine();\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; if (value.GetMethod != null)\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; {\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; codeStack.Push(new CodeStackItem(value.Name,\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; \"GetStatements\", true));\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; VisitMethodReference(value.GetMethod, false);\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; codeStack.Pop();\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; }\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; if (value.SetMethod != null)\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; {\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; codeStack.Push(new CodeStackItem(value.Name,\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; \"SetStatements\", true));\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; VisitMethodReference(value.SetMethod, false);\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; codeStack.Pop();\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; }\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; formatter.WriteLine();\n&#160;&#160; }\n}\n&#160;\n<\/pre>\n<p>There are a couple of key things to note here, the use of a new class <b>IndentedCodeBlock<\/b>, the declaration of <b>CodeDomTypes<\/b>, and the call to <b>VisitType <\/b>to create the code necessary to initialize the data type for the property.<\/p>\n<p><b>VisitType<\/b> is a function similar to the <b>VisitExpression<\/b> that we saw earlier.&#160; This method will be able to process type specification in all its forms.<\/p>\n<p>When dealing with one of the Declaration methods, we will be outputting a method that will produce the <b>CodeDom<\/b> code to create the corresponding object.&#160;&#160; In this case, we output the method <b>CreateProperty<\/b>&lt;PropertyName&gt;.&#160;&#160; We call <b>VisitType<\/b> passing in the context of the <b>CodeMemberProperty<\/b> and the Type property specifying that this is not a collection.&#160;&#160; We then call <b>VisitMethodReference<\/b> passing in the context of the <b>CodeMemberProperty<\/b> and the <b>GetStatements<\/b> and<b> SetStatements<\/b> specifying that these are collections.&#160;&#160; This will handle generating the details for the property implementation. <\/p>\n<p>The<b> IndentedCodeBlock<\/b> is a class that I borrowed from the implementation of the PowerShell language.&#160; It is a very simple class consisting of only a constructor and the Dispose method, but simplifies formatting our code.&#160;&#160; We use this class whenever our outputted code adds a level of indention.<\/p>\n<pre class=\"lang:c# theme:vs2012\">private class IndentedCodeBlock : IDisposable\n{\n&#160;&#160;&#160; private readonly IFormatter formatter;\n&#160;\n&#160;&#160;&#160; public IndentedCodeBlock(IFormatter formatter)\n&#160;&#160;&#160; {\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; this.formatter = formatter;\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; formatter.Write(\"{\");\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; formatter.WriteLine();\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; formatter.WriteIndent();\n&#160;&#160;&#160; }\n&#160;\n&#160;\n&#160;&#160;&#160; public void Dispose()\n&#160;&#160;&#160; {\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; formatter.WriteOutdent();\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; formatter.Write(\"}\");\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; formatter.WriteLine();\n&#160;&#160;&#160; }\n}\n<\/pre>\n<p>By declaring the <b>IndentedCodeBlock<\/b> in a using statement, we don&#8217;t have to worry about explicitly calling the dispose.&#160; The I<b>ndentedCodeBlock<\/b> &#160;will go out of scope as soon as the using statement is out of context and the Dispose method will be called automatically.&#160;&#160; <\/p>\n<p>There are a couple of lines worth noting here.&#160; We call some new functions from the formatter to control the layout of the code.&#160; &#160;There are various methods that we can call to facilitate color coding and make our outputted code more visually engaging.&#160;&#160; The actual results will depend on the implementation of the <b>IFormatter<\/b> object.&#160;&#160; Providing your own <b>IFormatter<\/b> is yet another way to customize Reflector.&#160;&#160; Here are the important methods in the <b>IFormatter<\/b> interface:<\/p>\n<table>\n<tbody>\n<tr>\n<td valign=\"top\">\n<p class=\"BOLD\">Write<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"TableContents\">Called to write out a string with no special formatting.<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"BOLD\">WriteComment<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"TableContents\">Called to write out a string formatted as a comment.&#160;&#160; This will generally be a light gray.&#160;&#160; These are not the comments from the original code but comments that the language added while translating.<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"BOLD\">WriteDeclaration<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"TableContents\">Called to write out the keywords in a declaration.<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"BOLD\">WriteIndent<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"TableContents\">Called to write out a new level of indentation in your code.<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"BOLD\">WriteKeyword<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"TableContents\">Called to write out a Keyword.<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"BOLD\">WriteLine<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"TableContents\">Called to write out a new line.&#160; This signals to the formatter that this is the end of one line and that futures calls should display text on a new line.<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"BOLD\">WriteLiteral<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"TableContents\">Called when you need to write out a literal value such as a string, a number, a Boolean value, etc.<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"BOLD\">WriteOutdent<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"TableContents\">Called to end the most recent level of indentation in your code.<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"BOLD\">WriteProperty<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"TableContents\">Called to write out a property reference<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"BOLD\">WriteReference<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"TableContents\">Called to write out a function reference<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h2>Taking this Further<\/h2>\n<p>Here we showed how to create a language that will produce the CodeDom code to represent the code being disassembled.&#160; Other possibilities may include using this framework to create a language to provide static code analysis.&#160;&#160; You have the pieces needed to build a rules engine similar to FxCop.&#160;&#160; You could complain about methods with too many parameters.&#160;&#160; Warn about methods with too many conditional branches.&#160;&#160; Raise red flags when a switch statement does not include a &#8220;default&#8221;.&#160;&#160;&#160; <\/p>\n<p>You could also use this approach to build a language that would write stubs for your unit testing.&#160;&#160; As your language visits language structures such as an <b>IConditionStatement<\/b>, <b>ISwitchCase<\/b>, or <b>IForEachStatemen<\/b>t that would indicate the need for a new unit test, your language could output a comment describing the new test that would be needed.<\/p>\n<p>In the approach outlined here, we mainly used the Write and WriteLine methods.&#160; The other methods provided by <b>IFormatter<\/b> can be used to provide syntax highlighting for your language output.&#160;&#160;&#160; Using these methods will not add any functionality to our language or change its implementation, but it will improve the readability and look of your generated code.<\/p>\n<p>Also <b>WriteComment <\/b>can be used to add critiques of the code being parsed.<\/p>\n<h2>Screen Shots <\/h2>\n<p>Here is how our new language looks in Reflector.&#160; We load this add-in like we would an add-in.&#160;&#160; Once added, our &#8220;language&#8221; shows up in the language drop down.<\/p>\n<p class=\"ILLUSTRATION\"><img loading=\"lazy\" decoding=\"async\" height=\"468\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/imported\/829-image002.jpg\" width=\"624\" alt=\"829-image002.jpg\" \/><\/p>\n<p class=\"ILLUSTRATION\"><img loading=\"lazy\" decoding=\"async\" height=\"432\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/imported\/829-image004.jpg\" width=\"624\" alt=\"829-image004.jpg\" \/><\/p>\n<h2>Conclusion<\/h2>\n<p>Creating your own Reflector language should not be seen as daunting task.&#160; The goal is not to create a new industrial grade language and compete with C# and VB.&#160;&#160; The goal is to provide a new way to translate IL into something useful.&#160;&#160;&#160; Here we discussed examples of what you may do with your own language.&#160;&#160; As you get comfortable with these techniques, you will find more uses and new ways to have fun with a remarkable tool: .NET Reflector.<\/p>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>.NET Reflector was the first .NET tool to allow assemblies to be disassembled back into the high level language that produced them. Moreover, it has a plug-in architecture that allows you to disassemble to any language for which you have a plug-in, or are prepared to write one. Nick Harrison takes it one further step, and creates a plug-in that produces the CodeDom code needed to create the contents of the assembly. Nick explains, gently.&hellip;<\/p>\n","protected":false},"author":221853,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[143538],"tags":[4143,4229,5058,4885],"coauthors":[],"class_list":["post-695","post","type-post","status-publish","format-standard","hentry","category-dotnet-development","tag-net","tag-net-framework","tag-example-sample-code-net-reflector-plug-in-plugin-codedom","tag-reflector"],"acf":[],"_links":{"self":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/695","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/users\/221853"}],"replies":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/comments?post=695"}],"version-history":[{"count":5,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/695\/revisions"}],"predecessor-version":[{"id":91132,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/695\/revisions\/91132"}],"wp:attachment":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/media?parent=695"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/categories?post=695"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/tags?post=695"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/coauthors?post=695"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}