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:
- In C#, the programmer writing an instance method can leave off this when referring to instance members; CodeDom insists on it being there.
- 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.
Comments
- Anonymous
April 10, 2006
> The Forms Designer in Visual Studio 2005 takes away a lot of the drudgery of GUI development
well - if it works. which, quite often, it doesn't.
WM_FYI
thomas woelfer - Anonymous
April 10, 2006
+1 to thomas.
It's just like the fact that you couldn't (for some reason) generate a protected override for a method in 2003. It would generate as just protected.
Benet,
I can't tell you how much I've worked with CodeDom and was frustrated by how useful it could be and how half-baked it actually is.
I would appreciate if one the guys over at the BCL team read my weblog and especially this[1] (note: this is NOT for self-promotion), because comments here are too short to describe my experiences, may they be good and bad.
[1] http://weblogs.asp.net/okloeten/archive/2006/04/08/442298.aspx - Anonymous
April 10, 2006
The comment has been removed - Anonymous
April 10, 2006
Eric - i'm not talking about a hiccup. i'm talking about this is, by and large, doesn't work over here. some forms take 10 minutes (!) to load. attempting to load others, sometimes simply removes the ide from memory. others will simply hang the ide. just random.
yes - it does work with every single test application i ever wrote and it works with all of our "simple" solutions/projects. but its practically unuseable for our (largish) main solution. - Anonymous
April 10, 2006
The comment has been removed - Anonymous
April 12, 2006
The comment has been removed - Anonymous
April 12, 2006
Benet,
First of all, my name is Omer. Don't worry, you're not the first to get confused :)
Secondly, My apologies about the params bug. This was tested on VS2003.
On the other hand, having the ability to to this instead would have proved more understandable and would eliminate the bug of errornously declaring two or more param arrays:
myMethod.Parameters.Params = new CodeParameterDeclarationExpression(...); - Anonymous
April 17, 2006
The comment has been removed - Anonymous
April 20, 2006
Dear BCL Team,
Please use full text feeds in your RSS.
Thank you. - Anonymous
April 21, 2006
Thanks for the post. I am always interested in information on the CodeDom. I have often found it very useful and frequently advocate its use.
One item that has been causing me some problems is with logical operators. Do you have any guidance on how to generate compound conditionals for the CodeConditionStatements?
if ((Condition1) || (Condition2))
or
if ((Condition1) && (Conditon2))
Thanks - Anonymous
April 21, 2006
Nick,
Compound conditionals can be created by nesting CodeBinaryOperatorExpressions.
Example:
new CodeBinaryOperatorExpression(Condition1, CodeBinaryOperatorType.BooleanAnd, new CodeBinaryOperatorExpression(Condition2, CodeBinaryOperatorType.BooleanOr, Condition3))
Would generate:
(Condition1 && (Condition2 || Condition3))
For more info, you can check out the articles on my weblog.