Geek Noise
Rants, rambles, news and notes by Peter Provost
11

CodeSmith + CodeDom

Monday, 11 August 2003 14:09 by Peter Provost

Yesterday Steve Eichert wrote:

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:

private void button1_Click(object sender, System.EventArgs e)

{
CodeSmithTemplates.SimpleTemplate template =
new CodeSmithTemplates.SimpleTemplate();
template.ClassName = "MyClass";
template.SampleStringProperty = "MyProperty";
string source = template.RenderToString();

CSharpCodeProvider cSharpProvider = new CSharpCodeProvider();
ICodeCompiler compiler = cSharpProvider.CreateCompiler();

CompilerParameters options = new CompilerParameters();
options.GenerateInMemory = true;

CompilerResults results =
compiler.CompileAssemblyFromSource( options, source );

if( results.Errors.HasErrors )
{
StringBuilder sb = new StringBuilder();
foreach( CompilerError error in results.Errors )
{
sb.Append( String.Format("{0} - {1}\n", error.Line,
error.ErrorText ) );
}

MessageBox.Show( sb.ToString(), "ERROR" );
return;
}

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!

Currently rated 3.0 by 1 people

  • Currently 3/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5
Categories:   Technology
Actions:   E-mail | del.icio.us | Permalink | Comments (0) | Comment RSSRSS comment feed
Comments are closed