Practical Programming Pearls For .NET Developers

CodeDOM Cookbook

Created: 20 September 2008
Updated: 8 November 2008

Download the sample application.

Welcome to the CodeDOM Cookbook.  This is a multi-part series of articles on using the CodeDOM to generate code dynamically at runtime.  The CodeDOM is becoming more and more popular in applications and a good understanding is essential for using it properly.  The cookbook will begin with the basics of the CodeDOM, move through declaring types and members, discuss how to create programming statements such as if and while loops, cover the details of language directives and finally finish up with a discussion of some language-specific features.

CodeDOM meet Programmer,  Programmer meet the DOM

The CodeDOM is part of the core .NET framework and can be used to generate code programmatically at runtime, compiled into an assembly and then loaded and run.  The CodeDOM is used throughout the framework for automatic code generation and has been around since v1.0.  Automatic code generation is great for converting data into executable structures when the data is relatively static.  For example an ASP.NET theme file, an XML file or even a schema file could be converted to code and run rather than having to interpret the data file each time.

The CodeDOM is designed to be language-agnostic.  Any language specific features (such as VB's With statement or C#s ?: operator) are not supported by the DOM.  Furthermore the DOM doesn't always keep pace with the changing language features.  Therefore some newer functionality (such as generics) may have limited or no DOM support.  Finally not every language feature results in the generation of specific code.  Some language features (such as LINQ or variable declaration/initialization) are just shorthand for the longer blocks of code.  The DOM is designed to generate code.  It is not designed to generate code that is necessarily readible or concise compared to hand-generated code.  Therefore some programmer-friendly features are either not supported at all or rarely used with the DOM (such as comments).

A final note about the DOM.  It is not necessary, or even recommended, for all code generation scenarios.  Writing and debugging DOM code can be difficult and frustrating.  Furthermore access to the generated code requires either reflection or the use of an interface or base class that is pregenerated.  Therefore it is generally best to use base classes, interfaces and source code template files to generate most code and use the DOM only when it is necessary.  The key is to isolate the common code into pregenerated code/templates and only use the DOM for specific portions of the code.

Introducing ConfigGen

Ideally it would be nice to create a tool that you could pass some real code to and have it generate the DOM logic for.  Unfortunately this is not possible without a lot of work.  The problem lies in the fact that there is no standard mechanism available to get access to the statements contained in a method body.  VS exposes the object model for a file but it does not go down to the statement level.  Reflection will return type and member information but also will not go down to the statement level.  You can get the IL directly but then you would have to parse the data.  Some tools like FxCop, Reflector or Phoenix can get the desired information but they would require that you have them installed.  None of these options sound great to me.

Instead the example code will be for ConfigGen.  ConfigGen is a tool I started writing to go along with my article on creating custom configuration sections.  ConfigGen takes a properly formatted XML section and converts it to a .NET custom configuration section.  For purposes of this article we will add the code generation logic piecemeal as we cover things.  Therefore we will not be generating valid configuration section code that can be used with the configuration subsystem until late in the series.

Since the purpose of these articles is to use the DOM we will not focus on the program itself.  A brief overview is in order though.  When the program starts a new project is automatically created.  The project acts as a simple folder placeholder for the target XML and the generated files.  It contains some settings that control code generating including the target language and the namespace to house the types.  The user will paste some (valid) XML into the text editor.  The user can also choose the language to generate the code in.  When the user clicks the button to build the code a background worker thread will start parsing the XML and generating the DOM model.   

The ConfigurationGenerator class is responsible for parsing the XML and generating the code.  It sends status messages back to the UI as it runs.  If any XML parsing errors occur or the XML is not valid for a configuration section then code generation will fail.  The generator enumerates the XML and generates the appropriate code using the DOM.  We will not discuss the XML parsing unless it is relevant to the DOM.  To keep things simple the generator will be responsible for parsing the XML, generating the code and reporting status.  In a real-world application this functionality would likely be broken up.

  1. Chapter 1 - Basics
  2. Chapter 2 - Types
  3. Chapter 3 - Type Members
  4. Chapter 4 - Type Members - Methods
  5. Chapter 5 - Expressions
  6. Chapter 6 - Statements
  7. Chapter 7 - Advanced Class Members
  8. Chapter 8 - Comments and Directives
  9. Chapter 9 - Language-specific Features
  10. Chapter 10 - Generics