Click here to Skip to main content
15,889,116 members
Articles / Programming Languages / C#
Article

Evaluate C# Code (Eval Function)

Rate me:
Please Sign up or sign in to vote.
4.74/5 (48 votes)
12 Oct 2005CPOL 418.6K   4.9K   130   35
An example that provides an Eval function for compiling/evaluating C# code at runtime.

Sample Image - EvalCSCode.jpg

Introduction

This example shows an "Eval" function for C# and implements different usages of this evaluate function. The library is written in C# and can be tested with the MainForm in the solution.

Source view

Here you will see all the trick. The code generates a class structure with a basic "function prototype" in which the code to evaluate is filled in. The execution of the function should execute your code:

C#
// Eval > Evaluates C# sourcelanguage
public static object Eval(string sCSCode) {

  CSharpCodeProvider c = new CSharpCodeProvider();
  ICodeCompiler icc = c.CreateCompiler();
  CompilerParameters cp = new CompilerParameters();

  cp.ReferencedAssemblies.Add("system.dll");
  cp.ReferencedAssemblies.Add("system.xml.dll");
  cp.ReferencedAssemblies.Add("system.data.dll");
  cp.ReferencedAssemblies.Add("system.windows.forms.dll");
  cp.ReferencedAssemblies.Add("system.drawing.dll");

  cp.CompilerOptions = "/t:library";
  cp.GenerateInMemory = true;

  StringBuilder sb = new StringBuilder("");
  sb.Append("using System;\n" );
  sb.Append("using System.Xml;\n");
  sb.Append("using System.Data;\n");
  sb.Append("using System.Data.SqlClient;\n");
  sb.Append("using System.Windows.Forms;\n");
  sb.Append("using System.Drawing;\n");

  sb.Append("namespace CSCodeEvaler{ \n");
  sb.Append("public class CSCodeEvaler{ \n");
  sb.Append("public object EvalCode(){\n");
  sb.Append("return "+sCSCode+"; \n");
  sb.Append("} \n");
  sb.Append("} \n");
  sb.Append("}\n");

  CompilerResults cr = icc.CompileAssemblyFromSource(cp, sb.ToString());
  if( cr.Errors.Count > 0 ){
      MessageBox.Show("ERROR: " + cr.Errors[0].ErrorText, 
         "Error evaluating cs code", MessageBoxButtons.OK, 
         MessageBoxIcon.Error );
      return null;
  }

  System.Reflection.Assembly a = cr.CompiledAssembly;
  object o = a.CreateInstance("CSCodeEvaler.CSCodeEvaler");

  Type t = o.GetType();
  MethodInfo mi = t.GetMethod("EvalCode");

  object s = mi.Invoke(o, null);
  return s;

}

Thanks fly out to:

Credits:

  • Kim Hauser (dave) - Application Developer & System Engineer.

License

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


Written By
Software Developer (Senior)
Switzerland Switzerland
programmer and software junkie since 1991 zurich switzerland

Comments and Discussions

 
AnswerRe: Uses Pin
kim.david.hauser2-Nov-05 11:03
kim.david.hauser2-Nov-05 11:03 
GeneralThanks for review... Pin
kim.david.hauser21-Oct-05 10:13
kim.david.hauser21-Oct-05 10:13 
QuestionUsing a static method instead Pin
19-Oct-05 20:07
suss19-Oct-05 20:07 
AnswerRe: Using a static method instead Pin
aprenot21-Oct-05 10:17
aprenot21-Oct-05 10:17 
GeneralRe: Using a static method instead Pin
Toli Cuturicu20-Dec-10 11:22
Toli Cuturicu20-Dec-10 11:22 
GeneralExcellent! But Pin
cccccbbbbb19-Oct-05 14:41
cccccbbbbb19-Oct-05 14:41 
GeneralRe: Excellent! But Pin
kim.david.hauser22-Oct-05 0:29
kim.david.hauser22-Oct-05 0:29 
AnswerRe: Excellent! But Pin
Kevan Davis1-Dec-06 11:18
Kevan Davis1-Dec-06 11:18 
Used this is a project I'm working on. It's a slight modification of what you posted.
I also tried to figure out the AppDomain, this is where I got when I ran into a brick wall.
In order to load the code into the new AppDomain, you will need 2 classes, the first class creates the AppDomain, and loads the 2nd class into it, similar to what I have at the bottom. The second class will inherit MarshalByRefObject and will do all the dynamic compilation.
When/if I get around to finishing this, I'll post it as well.

<br />
using System;<br />
using System.CodeDom.Compiler;<br />
using System.Collections.Generic;<br />
using System.Text;<br />
using System.Windows.Forms;<br />
using Microsoft.CSharp;<br />
<br />
namespace Test<br />
{<br />
    /// <summary><br />
    /// C# Code Evaluator<br />
    /// Based on work by Kim Hauser found at http://www.codeproject.com/csharp/evalcscode.asp<br />
    /// </summary><br />
    class CSEvaluator<br />
    {<br />
        /// <summary><br />
        /// Assemblies are what follow "using"<br />
        /// </summary><br />
        public List<string> Assemblies;<br />
        /// <summary><br />
        /// References are in the Solution Explorer in the References folder<br />
        /// </summary><br />
        public List<string> References;<br />
        /// <summary><br />
        /// Namespace to evaluate in, in case you want to be able to access external classes<br />
        /// </summary><br />
        public string Namespace;<br />
<br />
        public CSEvaluator()<br />
        {<br />
            References = new List<string>();<br />
            // Adding default References<br />
            References.Add("System");<br />
            References.Add("System.Drawing");<br />
            References.Add("System.Windows.Forms");<br />
            References.Add("System.Xml");<br />
<br />
            Assemblies = new List<string>();<br />
            // Adding default assemblies<br />
            Assemblies.Add("System");<br />
            Assemblies.Add("System.Drawing");<br />
            Assemblies.Add("System.Drawing.Drawing2D"); // notice that Drawing2D is not in the list of references<br />
            Assemblies.Add("System.Windows.Forms");     //    this is because System.Drawing is the reference for it<br />
            Assemblies.Add("System.Xml");<br />
<br />
            Namespace = this.GetType().Namespace.ToString();<br />
        }<br />
<br />
        /// <summary><br />
        /// Evaluates C# Code<br />
        /// </summary><br />
        /// <param name="sCSCode">The Code to evaluate</param><br />
        /// <param name="sParms">parameter string, i.e. "string sCSCode, string sParms, object[] oParms"</param><br />
        /// <param name="oParms">array of parameter objects</param><br />
        /// <returns></returns><br />
        public object Eval(string sCSCode, string sParms, object[] oParms)<br />
        {<br />
            CompilerParameters cp = new CompilerParameters();<br />
<br />
            // load references<br />
            foreach (string r in References)<br />
                cp.ReferencedAssemblies.Add(r + ".dll");<br />
<br />
            cp.CompilerOptions = "/t:library";<br />
            cp.GenerateInMemory = true;<br />
<br />
            StringBuilder sb = new StringBuilder("");<br />
            // load assemblies<br />
            foreach (string s in Assemblies)<br />
                sb.Append("using " + s + ";\n");<br />
<br />
            sb.Append("\nnamespace " + Namespace + "\n{\n");<br />
            sb.Append("\tpublic class temp_Eval\n\t{\n");<br />
            sb.Append("\t\tpublic object Eval(" + sParms + ")\n\t\t{\n");<br />
            sb.Append("\t\t\treturn " + sCSCode + "; \n");<br />
            sb.Append("\t\t}\n");<br />
            sb.Append("\t}\n");<br />
            sb.Append("}\n");<br />
<br />
            CompilerResults cr = CodeDomProvider.CreateProvider("CSharp").CompileAssemblyFromSource(cp, sb.ToString());<br />
            if (cr.Errors.Count > 0)<br />
            {<br />
                MessageBox.Show("ERROR: " + cr.Errors[0].ErrorText,<br />
                   "Error evaluating cs code", MessageBoxButtons.OK,<br />
                   MessageBoxIcon.Error);<br />
                return null;<br />
            }<br />
<br />
            // *** Below this point is a work in progress, watch out for falling debris ***<br />
<br />
            //AppDomain evalDomain = AppDomain.CreateDomain("evalDomain");<br />
            System.Reflection.Assembly a = cr.CompiledAssembly;<br />
            //evalDomain.DefineDynamicAssembly(a.GetName(), System.Reflection.Emit.AssemblyBuilderAccess.Run); // problem here can be solved with MarshalByRefObject<br />
            //object o = evalDomain.CreateInstance(a.GetName().ToString(), Namespace + ".temp_Eval"); // it probably won't work like this<br />
            object o = a.CreateInstance(Namespace + ".temp_Eval");<br />
<br />
            Type t = o.GetType();<br />
            System.Reflection.MethodInfo mi = t.GetMethod("Eval");<br />
<br />
            object ec = mi.Invoke(o, oParms);<br />
<br />
            //AppDomain.Unload(evalDomain);<br />
            return ec;<br />
        }<br />
    }<br />
}<br />

GeneralExcellent !! Pin
Tittle Joseph18-Oct-05 19:46
Tittle Joseph18-Oct-05 19:46 
GeneralThanks, but ... Pin
Herman Chelette18-Oct-05 2:33
Herman Chelette18-Oct-05 2:33 
GeneralRe: Thanks, but ... Pin
kim.david.hauser21-Oct-05 9:34
kim.david.hauser21-Oct-05 9:34 
GeneralGreat Job Pin
aprenot13-Oct-05 5:02
aprenot13-Oct-05 5:02 
GeneralRe: Great Job Pin
Anonymous21-Oct-05 9:52
Anonymous21-Oct-05 9:52 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.