This post originated from an RSS feed registered with .NET Buzz
by Peter G Provost.
Original Post: CodeSmith + CodeDom
Feed Title: Peter Provost's Geek Noise
Feed URL: /error.aspx?aspxerrorpath=/Rss.aspx
Feed Description: Technology news, development articles, Microsoft .NET, and other stuff...
This past week while working on a re-write of the framework that prompted the initial
evaluation of Emit vs. CodeDOM I decided to revisit the debate. After "thumbing"
my way through the documentation of the CodeDOM classes I came across the ICodeCompiler.CompileAssemblyFromSource()
method. Rather then emitting OpCodes I decided to create a couple of templates
for my code and use the ICodeCompiler to genearte an in memory assembly. While
I did miss the process of pushing things onto the call stack using OpCodes, I realized
how much more productive I was creating "C# templates" for my code and compiling them
with the CodeDOM classes.
As I started to think about this, I decided to try this out. Since CodeSmith will
produce a template assembly that I can call from code, this should be easy as pie!
I started by creating this simple CodeSmith template:
<%@
CodeTemplate Language="C#" TargetLanguage="C#" Description="" %> <%@
Property Name="ClassName" Type="System.String" Default="MyClass"
Category="Options" Description="" %> <%@
Property Name="SampleStringProperty" Type="System.String"
Default="SampleString" Category="Options" Description="" %>
public class <%=ClassName%>
{
public string <%= SampleStringProperty %>
{
get { return _<%=SampleStringProperty%>;
}
set { _<%=SampleStringProperty%> =
value; }
}
private string _<%=SampleStringProperty%>;
}
Then using CodeSmith, I created
an assembly from my template. Basically this creates a DLL that you can reference
from your code that contains the code generation class defined by the CST file.
Once that was done, I created a simple forms app, added a button, and put the following
code in the click handler:
Assembly assembly = results.CompiledAssembly;
object o = assembly.CreateInstance( "MyClass" );
Type t = o.GetType();
t.InvokeMember( "MyProperty", BindingFlags.SetProperty, null,
o, new object[] { "Test!" } );
object result = t.InvokeMember( "MyProperty",
BindingFlags.GetProperty, null, o, null );
MessageBox.Show( result.ToString() );
}
That's it! Granted I didn't do anything particularly complex with it, but it is a
very effective way to combine template generated code (a la CodeSmith)
with CodeDom. Enjoy!