By the way, to anyone thinking about doing some
CodeDom development be sure to avoid the
CodeSnippetExpression class like the plague. It turns out there is (at least) two legitimate usages of the class that I have encountered but otherwise it is evil.
I can say this because I just spent a couple weeks re-doing all of my templates so that the
CodeSnippetExpression class was completely removed from my templates. This was only the beginning of the headache of making my
CodeDom code language agnostic but it was the most painful. For the record I'll add my two legitimate usages of snippets and some examples of how I got burned by just saying to myself "
Meh, I'll only be generating C# anyway...".
Legitimate use #1 - Calling the default base class constructor//Example
CodeConstructor c = new
CodeConstructor();
c.Name = "Example";
c.Attributes =
MemberAttributes.Public;
c.BaseConstructorArgs.Add(new
CodeSnippetExpression(""));
//Output
Example() : base() { }
For some reason you have to add a parameter to the
BaseConstructorArgs collection to get this functionality and if you want to call the
parameterless constructor you have to add an expression that generates nothing. I suppose you *might* be able to use the
CodePrimitiveExpression(null) but I haven't tried that. I can confirm that the empty
CodeSnippetExpression("") does work however.
Legitimate use #2 - Fake while loops//Example
CodeIterationStatement i = new
CodeIterationStatement(
new
CodeSnippetStatement(""),
new
CodePrimitiveExpression(true),
new
CodeSnippetStatement(""));
//Output
for(;true;) { }
Now I realize that this looks stupid but I assure you, it's legitimate. It turns out there is no "while" loop in the
CodeDom all you get is the
CodeIterationStatement which in turn generates a for loop. However if you think about it what is a for loop? Essentially you're saying "for some initial value, while some condition is true, do this". A for loop with only the condition evaluation is essentially a while loop and the only way to do that with the
CodeDom is to print out empty snippets.
So it's ironic that the only legitimate usages of the
CodeSnippetExpression objects are simply empty strings. This makes me think that they're utterly evil and should instead be replaced with a
CodeEmptyExpression() object or something similar. I welcome any comments about how else they could be properly used.
Here are a few simple
examples about how I decided to use them then found it to be very painful to undo them:
Bad idea: "using"Yes I know the "using" feature in C# is lovely and wonderful and all of that but in reality it is simply
syntactic sugar. It is not part of the underlying .net framework.
Proper Alternative:IDisposable d = ...;
try
{
//do something to d.
}
finally
{
d.Dispose();
}
This is essentially what the "using" statement is doing under the hood. Unfortunately you have to implement this using the
CodeDom this robustly. There are no language agnostic shortcuts!
Bad Idea: "anonymous delegates"Anonymous delegates, oh anonymous delegates, how I love thee... unfortunately you are simply an illusion! Once again more C# syntactic sugar. What's going on under the hood is that a private member is getting generated and a delegate pointing to that method is being generated for you. You're going to have to do it all yourself! Additionally, simply passing method names as parameters for delegates isn't good enough either, more damn syntactic sugar! You're going to have to do it all the hard way.
Proper Alternative:void Test()
{
EventHandler e = new
EventHandler(Test);
e.Invoke(this,
EventArgs.Empty);
}
void
MyDelegateMethod(object sender,
EventArgs e)
{
//do something.
}
This goes for asynchronous methods as well. In stead of simply passing in Method names for parameters you'll need to use the
CodeObjectCreate class to create an instance of your delegate (
EventHandler or whatever) and pass in the Method name to that. Make sure you use all the proper
CodeDom classes to get this language agnostic.
Those were really the biggest gotchas that I found out. You should start out assuming you're going to be generating for multiple languages and do it right the first time. Be sure to find the right class for the right job too!