Click here to Skip to main content
15,893,668 members
Articles / Desktop Programming / Windows Forms

Dynamic Code Integration with CodeDom

Rate me:
Please Sign up or sign in to vote.
4.71/5 (26 votes)
23 May 2008CPOL8 min read 79.4K   1.2K   36  
While there are many expression evaluators out there, the CodeDom framework allows you to take any .NET langauge and link a code snippet at run-time.
<!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>

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Instructor / Trainer The Ohio State University
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions