Creating and Initializing Objects in CodeDom [Benet Devereux]

The Forms Designer in Visual Studio 2005 takes away a lot of the drudgery of GUI development. All you do is drag and drop the components you need onto a panel, arrange them where you want them, and VS will generate the code to initialize them automatically; all you need to do is write event-handlers. Out of the box, it will do this for C# and Visual Basic; and, as new languages are integrated into VS (such as IronPython), it can generate GUI setup code for them as well! How is it so flexible? The answer, of course: CodeDom.

 

Using CodeDom to create language-independent code for instantiating and initializing object graphs, as the Designer does, is quite simple. Here are some of the basic steps:

 

Creating an object

 

In C#, a System.Drawing.Size object is instantiated like this:

 

new Size(640, 400)

 

To create a CodeDom tree for the same expression is not too much more work:

 

CodeExpression newSizeExpr = new CodeObjectCreateExpression(new CodeTypeReference(“System.Drawing.Size”),

       new CodePrimitiveExpression(640), new CodePrimitiveExpression(400));

 

The first parameter is, clearly, a CodeTypeReference (note that the fully-qualified name is necessary; there’s no using in CodeDom) of the desired type, and the remaining parameters are the arguments to the constructor to be used. Whether the arguments you gave can be bound to a valid constructor won’t be checked until the tree is processed by a provider, so be careful! CodeDom won’t stop you from writing, instead,

 

CodeExpression newSizeExpr = new CodeObjectCreateExpression(new CodeTypeReference(“System.Drawing.Size”),

       new CodePrimitiveExpression(“bigger than the biggest thing ever and then some”));

 

Storing the object

 

There’s not much point creating an object if we don’t put it someplace. Suppose the Size object created in the previous expression is the initialization of the ClientSize property of a Form. In the form’s initialization method, you’ll see a line of code like:

 

ClientSize = new Size(640,400)

 

We already have the expression for the object creation stored in newSizeStmt, so creating the corresponding CodeStatement is simple:

 

CodeExpression thisExpr = new CodeThisReferenceExpression()

CodeStatement clientSizeStmt = new CodeAssignStatement(

    new CodePropertyReferenceExpression(thisExpr, “ClientSize”),

    newSizeExpr)

 

A CodeAssignStatement has, naturally, a left-hand and right-hand side expression. On the left-hand side we have a CodePropertyReferenceExpression, created from an object expression (in this case just this) and a property name given as a string. On the right-hand side is newSizeExpr. Of course, the CodeDom tree for the whole statement could be generated in a single line of code, at the expense of some readability.

 

There are two things to note here:

  1. In C#, the programmer writing an instance method can leave off this when referring to instance members; CodeDom insists on it being there.
  2. CodeDom is language-agnostic, so it will allow you to put in any kind of expression as the left-hand side of an assignment statement, not just what C# or VB or some other language considers to be a valid lvalue. You can create the assignment statement 3 = “three” as a CodeDom tree, and not see any problems until a provider tries to compile it. Most compilers will refuse!

 

One of CodeDom’s uses, as we can see from this example, is to provide a fairly simple, maintainable way to create and store boilerplate code that can be parameterized and reused in different settings and even different languages.