Creating and Initializing Objects in CodeDom [Benet Devereux]

Creating and Initializing Objects in CodeDom [Benet Devereux]

  • Comments 13

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.

  • >> 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
  • +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
  • I think Tom is being a little hard on the CodeDom and VS in general.  We have all had it hiccup, but by and large my experience with the GUI designer is that it just works.
  • 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.
  • More often than not, I've found any instability of the VS 2005 designer is as a result of poor component / control coding, either my own or from a third party. Arguably, VS should deal with such code more gracefully.

    You can help figure out what's going on by starting two VS instances, debug the first from the second, and then open the offending form in the first. Step through the code and see if anything dodgey occurs (eg. exceptions, infinite loops).

    I haven't had cause to use CodeDOM myself so can't really comment on it.

    Kent
  • Omer,

    Thank you for your feedback! Let me address the first issue listed in your blog entry briefly (though we’ll certainly be looking into them both).

    C#'s params keyword is syntactic sugar for the ParamArray pseudo-custom attribute. While the C# compiler will throw an error if you try to use the ParamArrayAttribute on a parameter rather than its keyword, the C# CodeDomProvider handles it. If you have a CodeParameterDeclarationExpression myMethodParam (of array type) and give it parameters with the following code:

    myMethodParam.CustomAttributes.Add(new CodeAttributeDeclaration("System.ParamArrayAttribute"));


    then the C# provider will handle it: if you ask for code to be generated, you'll see a params keyword rather than the explicit attribute declaration, and if you compile directly to an assembly it will also work.

    Benet
  • 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(...);
  • I'm now at the point where I've reverted to VB 2003 because the Forms Designer in VB 2005 just doesn't work.  Try having some components in one project, components that are composed by the first components in a second project, and then another project where you have forms based on your own Form base classes that contains those components.  When opening the solution it all works,a dn that is about the only time it all works.  As soon as you start changing code, everything gets out of sync and the only thing you can see is a designer-error.  I'm eagerly awaiting SP1, untill then, it'll be VB 2003, despite the lack of Generics, Refactoring and Edit And Continue.
  • Dear BCL Team,

    Please use full text feeds in your RSS.

    Thank you.
  • 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
  • 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.
Page 1 of 1 (13 items)