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