As I mentioned earlier, i’ve been working on a personal project in the few short hours I can steal each week. Whilst I’m not ready to talk about the project itself, I did come across a particular situation I thought may be of interest.
The problem I had to solve was creating a class that would return a simple constant value. It had to implement a certain interface however and, for various reasons, it wasn’t as simple as assigning the value to the class to return. I needed to hard code the value into the class, but I needed to do it at runtime (so the value can be different for each instantiation.) Basically, I needed to compile and create an instance of the object at run-time, with dynamically generated source code for the object itself.
Turns out, .Net 2.0 makes that quite easy. Heres how it’s done:
How you generate your source-code is an issue all in itself, and was fairly simple in this case, but what you need is a string variable that contains the source code for the class you want to compile. It needs to be complete as the system will compile it to an assembly. An example is below:
string code =
“using system;” +
“namespace ExampleCode.Source {” +
“public class helloWorld {” +
“private string displayString; ” +
“public helloWorld() {“
“displayString = “Hello World!”; }” +
“public string DisplayString() {” +
“return displayString;}” +
“}}”;
What you need then is the fully qualified type name of the class you want to instantiate. In this case it’s going to be:
string typeName = “ExampleCode.Source.helloWorld”;
Compiling is a simple matter of calling the CompileAssemblyFromSource method of a CSharpCodeProvider. A similar provider exists for VB.Net
CSharpCodeProvider compiler = new CSharpCodeProvider();
You need to pass in parameters however that visual studio normally takes care of for you, in particular the libraries to link to.
CompilerParameters compilerParams = new CompilerParameters(new string[] { “System.dll” });
The constructor parameters listed here is simply and array containing the name of every type you want to link to the assembly you are about to compile. System dlls and those of the current project can normally be added with a name only, for others you may need a full pathname.
CompilerParameters includes a lot of other functionality for controlling how the compilation project works, you may wish to check it out if you’re compiling something more complicated.
CompilerResults results = compiler.CompileAssemblyFromSource(compilerParams, new string[] { code });
All you need is a set of parameters and the code to compile and you’ve got an assembly. The results returned contains a lot of information about how the compilation went and may contain a list of errors if the compile wasn’t successful. You may have to output them and check while you’re first setting up to catch the little typos and logic errors that creep in to your dynamic code. What it will also contain is the in-memory representation of the assembly itself.
Getting your object instantiation now is easy:
object hw = results.CompiledAssembly.CreateInstance(typeName);
If everything has worked you’ve now got an instance of your dynamic class, just like all your design time compiled classes. It’s an object only as your compiler knows nothing about it at runtime. You can get around this by having your class inherity from a base, or implement a known interface, and cast the object to one of these.
Hope this is helpful!