<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<!-- saved from url=(0066)http://www.codeproject.com/script/Articles/ViewHtml.aspx?aid=26312 -->
<HTML xmlns="http://www.w3.org/1999/xhtml"><HEAD><TITLE>CodeProject: Article HTML. Free source code and programming help</TITLE>
<META http-equiv=Content-Type content="text/html; charset=utf-8"><LINK
href="CodeDom_files/CodeProject.css" type=text/css rel=stylesheet>
<META content="MSHTML 6.00.6001.18023" name=GENERATOR></HEAD>
<BODY><!-- HTML for article "Dynamic Code Integration with CodeDom" by Crawfis\nURL: http://www.codeproject.com/KB/dotnet/CodeDomDelegates.aspx
Copyright 2008 by Crawfis\nAll formatting, additions and alterations Copyright © CodeProject, 1999-2008 -->
<P><B>Please choose 'View Source' in your browser to view the HTML, or File |
Save to save this file to your hard drive for editing.</B></P>
<HR class="Divider subdue">
<DIV><SPAN id=ArticleContent>
<H2>Introduction</H2>
<P>I occasionally implement a program where I wish I could either change some
parameters interactively or re-write a portion of code interactively. The
parameters are easily solved with existing GUI components. The .NET framework
with the <CODE>System.CodeDom</CODE> namespace provides a nice suite of tools
for the latter. Several tutorials on using the CodeDom document exist, with most
of them focusing on creating a source code file. In .NET 2.0, support was added
to compile code from an internal string. This article will go over how to take a
section of code from say a text box and immediately use it within your system. I
will also go over a few simple use cases that allow you to take a single
expression or calculation from the user and embed that into a delegate function
or your own interface hidden from the user. In part II, I will provide some
robustness issues, provide additional examples, and discuss the utility of this
with respect to the new LINQ technology. Note, I will use C# to explain this,
but the concept will work equally well with any .NET language.</P>
<H2>Initial Set-up</H2>
<P>For this part of the tutorial, we will focus on a simple task: Outputting a
string to the console. Let us start with this simple program and see how we can
refactor it to allow for more flexibility. The article is long, but mainly
because I am going to take baby steps and repeat sections of the code as they
are refactored. I am also going to ignore any error checking or exceptions until
the end of the tutorial. Consider this very simple console application.</P><PRE lang=cs>class Foo
{
public void Print()
{
System.Console.WriteLine("Hello from class Foo");
}
}
static void Main( string[] args )
{
Foo myFoo = new Foo();
myFoo.Print();
}
</PRE>
<H2>Dynamic Compilation</H2>
<P>My end goal is to take source code in as a text string. So, as a first test,
I convert the code above to a string and then in <CODE>Main </CODE>I will create
an instance of <CODE>Foo</CODE> using the CodeDom technology, and Reflection.
This requires three steps:</P>
<UL>
<LI>Create an instance of an object that supports the
<CODE>ICodeCompiler</CODE> interface. For our purposes, we want an instance
which deals with C#, so we will use the <CODE>CSharpCodeProvider</CODE> in the
<CODE>Microsoft.CSharp</CODE> namespace.
<LI>Compile the source code into an Assembly.
<LI>Use Reflection on the Assembly to get information on the types and create
an instance of a type. </LI></UL>
<P>To aid in this, I will create a utility method called
<CODE>CompileSource</CODE> that will take in a string and output an Assembly.
Here is the code for this:</P><PRE lang=cs>private static Assembly CompileSource( string sourceCode )
{
CodeDomProvider cpd = new CSharpCodeProvider();
CompilerParameters cp = new CompilerParameters();
cp.ReferencedAssemblies.Add("System.dll");
cp.ReferencedAssemblies.Add("ClassLibrary1.dll");
cp.GenerateExecutable = false;
// Invoke compilation.
CompilerResults cr = cpd.CompileAssemblyFromSource(cp, sourceCode);
return cr.CompiledAssembly;
}
</PRE>
<P>Fairly straightforward, in addition to the creating the
<CODE>ICodeCompiler</CODE> and compiling the source, we needed to create a
<CODE>CompilerParameters</CODE> instance and configure it. Note that you can add
any references that you wish to expose to your users. The resulting Assembly is
extracted from an instance of the <CODE>CompilerResults</CODE> class that the
<CODE>CompileAssemblyFromSource</CODE> method returns. Okay, now let’s put this
to use. Below is the new application (minus the <CODE>CompileSource</CODE> code
above). I am using the string <CODE>@</CODE> operator to specify the source
code. With this syntax, any quotation marks in the string need to be
repeated:</P><PRE lang=cs dir=ltr>namespace CreateDelegate
{
class Program
{
static void Main( string[] args )
{
Test1();
}
private static void Test1()
{
//
// Create an instance of type Foo and call Print
//
string FooSource = @"
class Foo
{
public void Print()
{
System.Console.WriteLine(""Hello from class Foo"");
}
}";
Assembly assembly = CompileSource(FooSource);
object myFoo = assembly.CreateInstance("Foo");
// myFoo.Print(); // - Print not a member of System.Object
// ((Foo)myFoo).Print(); // - Type Foo unknown
}
}
}
</PRE>
<P>Note, <PLACE w:st="on" /><CODE>Main</CODE></PLACE /> has successfully created
an instance of the <CODE>Foo</CODE> class, but there are a few problems:</P>
<OL>
<LI><PLACE w:st="on" /><CODE>Main</CODE></PLACE /> has knowledge of the class
name (“Foo”) hard-coded within it.
<LI>When you compile this application, the type <CODE>Foo</CODE> does not
exist. It is created at run-time. As such, we have to use the unified type
<CODE>object</CODE> to deal with our instance of <CODE>Foo</CODE>. There is no
way to cast it to type <CODE>Foo</CODE>.
<LI>As a result of 2 above, I can not call <CODE>Print</CODE> using
<CODE>myFoo.Print</CODE>. That will produce a compiler error, as the type
<STRONG><CODE><STRONG>object</STRONG></CODE></STRONG> does not have a method
<CODE>Print</CODE>. </LI></OL>
<P>Hence the new version does not print anything. Using reflection, it is
possible to get the list of methods for the class <CODE>Foo</CODE> and to
<CODE>Invoke</CODE> the <CODE>Print</CODE> method directly. Doing so directly is
rather clumsy and not a very useful programming practice. Instead, I will cover
two approaches to dealing with these types that provide a more elegant
solution:</P>
<UL>
<LI>Programming to Interfaces
<LI>Using delegates </LI></UL>
<P>Both of these require additional knowledge in either the main program, the
source code string, or both. Which one to use depends on your application’s
particular needs and will be covered in the use cases later.</P>
<H2><EM>Programming to Interfaces</EM></H2>
<P>A fundamental tenant of modern software design is to <EM>program to
interfaces</EM>. For our simple example, we will add an <CODE>IPrint</CODE>
interface:</P><PRE lang=cs>namespace FooLibrary
{
public interface IPrint
{
void Print();
}
}
</PRE>
<P>I have placed this in the namespace <CODE>FooLibrary</CODE>. Having an
interface is not sufficient. It needs to be accessible to any classes that wish
to implement it. The best way to accomplish this is to place your key interfaces
into one or more type libraries (dll’s). I have created the dll IPrint.dll for
this project. I have also added it as a reference to our console application.
The modified test is as follows:</P><PRE lang=cs>using FooLibrary;
private static void Test2()
{
//
// Create an instance of type FooLibrary.IPrint and call Print
//
string FooInterface = @"
class Foo : FooLibrary.IPrint {
public void Print() {
System.Console.WriteLine(""Hello from class Foo"");
}
}";
Assembly assembly = CompileSource(FooInterface);
IPrint foo = assembly.CreateInstance("Foo") as IPrint
if (foo != null)
{
foo.Print();
}
}
</PRE>
<P>We have made the following changes:</P>
<OL>
<LI>We added a using statement for <CODE>FooLibrary</CODE>.
<LI>We cast the result of CreateInstance to the type <CODE>IPrint</CODE>
(using the <CODE>as</CODE> operator).
<LI>If the cast was successful, we can now call <CODE>Print</CODE>(). </LI></OL>
<P>In order for our string-based source code to compile, it needs access to the
type <CODE>IPrint</CODE> in the IPrint.dll assembly. Our
<CODE>CompileSource</CODE> method needs the following line added:</P><PRE lang=cs> cp.ReferencedAssemblies.Add("IPrint.dll");</PRE>
<P>Note that even though we include a using statement for
<CODE>FooLibrary</CODE>, we still need to fully qualify <CODE>IPrint</CODE>
within the string <CODE>fooSource</CODE>. This makes sense, since it is treated
as a separate compile unit. We could have also added an additional <CODE>using
FooLibrary</CODE> inside the string.</P>
<H2>Searching for Types Using Reflection</H2>
<P>This solves two of the three problems mentioned above. <CODE>Main</CODE>
still has a hard-coded reference to the string name “Foo”. Having the name of
the class hard-wired can easily be replaced with an additional user control,
letting the user specify the name of the type to create. This would be error
prone as the user changes the code, but perhaps forgets to change the name. To
remove the implementation intelligence of knowing the concrete type name from
<CODE>Main</CODE>, we can search the assembly. What we want is to take an
assembly and a well-known interface name and search for the concrete type name
that implements the interface. This is accomplished as follows:</P><PRE lang=cs>private static void Test2()
{
//
// Create an instance of type FooLibrary.IPrint and call Print
//
string FooInterface = @"
class Foo : FooLibrary.IPrint {
public void Print() {
System.Console.WriteLine(""Hello from class Foo"");
}
}";
Assembly assembly = CompileSource(FooInterface);
Type fType = assembly.GetTypes()[0];
Type iType = fType.GetInterface("FooLibrary.IPrint");
if (iType != null)
{
FooLibrary.IPrint foo = (FooLibrary.IPrint)
assembly.CreateInstance(fType.FullName);
foo.Print();
}
}
</PRE>
<P>Here, we made the assumption that there is only one type or the type we are
interested in is the first one. This can easily be changed to search through all
types and is left as an exercise to the reader. So, we can now create instances
of a type supporting our interface, where the type definition starts out
initially as a text string. If the end goal was simply to execute the statements
within the Print() method, then a simpler scheme can be constructed using
delegates which we will talk about next.</P>
<H2>Dynamic Delegates</H2>
<P>Let’s consider the case where we wish to allow the user to specify an
arbitrary two-dimensional function, f(x,y) using some user-interface component.
Here is an example:</P><PRE lang=cs>float func2D( float x, float y)
{
float value; value = Math.Cos(x) * Math.Sin(x) + 1.0f;
return value;
}
</PRE>
<P>There are many articles about creating your own expression engine and parsing
a function like this one. With CodeDom you can treat any .Net language as your
scripting language. How is this function different than our Print method above?
Well, for one it is not contained in a class or a namespace. You can use
reflection to access this function from the global namespace, but I am going to
take a different route. I am going to wrap it in a class so we can use similar
logic to above. I structured this code very specifically. The input I want from
the user is simply the line (or set of statements): </P><PRE lang=cs>value = Math.Cos(x) * Math.Sin(y) + 1.0f;
</PRE>
<P>This will alleviate the user from knowing the exact function signature, the
class name, interface name, etc. How? Through string manipulations! I define two
additional strings, called <CODE>methodHeader</CODE> and
<CODE>methodFooter</CODE>. I then take the string for the expression and
sandwich it between the header and footer strings before passing it to
<CODE>CompileSource</CODE> method. For example, the original example can be
coded like so: </P><PRE lang=cs>string FooSourcHeader = @"
using System;
class Foo {
static public void Print()
{";
string FooSourceFooter = @"
}
}";
string myPrint = FooSourcHeader
+ @"Console.WriteLine(""Embedded Hello"");"
+ FooSourceFooter;
Assembly fooAssembly = CompileSource(myPrint);
IPrint myFoo = fooAssembly.CreateInstance(“Foo”) as IPrint;
myFoo.Print();
</PRE>
<P>What is the advantage of doing this? Well, now I know that “Foo” is the class
name and that it implements the <CODE>IPrint</CODE> interface. I have control
over those strings! The user only needs to know that they are to provide a
sequence of zero or more statements. I can even provide a more detailed class
definition and tell the users which fields they have access to. Okay, so that is
cool, but this section is about dynamic delegates. A <CODE>delegate</CODE>
defines a type for a method signature. They are commonly used in callbacks and
with events. Any method with the same signature can be treated as the delegate’s
type. </P><PRE lang=cs> delegate void PrintDelegate();
private static void Test3()
{
//
// Get a PrintDelegate from an instance of the type Foo.
//
string FooSourcHeader = @"
using System;
class Foo {
static public void Print()
{";
string FooSourceFooter = @"
}
}";
string myPrint = FooSourcHeader
+ @"Console.WriteLine(""Hello from Print delegate"");"
+ FooSourceFooter;
Assembly assembly = CompileSource(myPrint);
//
// Try to Invoke a method
//
Type fooType = assembly.GetType("Foo");
MethodInfo printMethod = fooType.GetMethod("Print");
PrintDelegate fooPrint = (PrintDelegate)
Delegate.CreateDelegate(typeof(PrintDelegate), printMethod);
fooPrint();
}
</PRE>
<H2>Summary</H2>
<P>There you have it. We can use text strings to add functionality to our system
at run-time. We can allow full class definitions if we want or simple method
bodies. In part II I will provide some user controls and example demos built
with these ideas. I will also go over some robustness issues and how to present
any compiler errors back to the user. </P>
<P>
<H2>History</H2>
<P>Keep a running update of any changes or improvements you've made here.
</P></SPAN></DIV></BODY></HTML>