OdeToCode IC Logo

An Eval Function for C# using JScript.NET (JavaScript)

Sunday, January 4, 2004

Once I was faced with a scenario where we needed client specific calculations applied to the results of a SQL query. The situation cried out for a “eval” type method where we could just plug values into a custom equation and retrieve a result. VBScript, JScript.NET, and JavaScript all contain an eval method, where you can pass a string containing a valid expression for the language and retrieve a result – dynamic execution.

Unfortunately, C# does not provide an eval method. One solution is to add a JScript.NET project to your solution. It feels a bit messy to suddenly have an extra assembly to build and deploy just for 10 lines of JScript code. An alternate solution is to use the System.CodeDom namespace to compile a JScript class in memory to use.

The C# class below contains all static methods. Using the evaluator is as simple as:

Evaluator.EvalToInteger(“(9/6) + 3”);

Source code follows. To compile, make sure you add a reference to the Microsoft.JScript assembly. Most of the work in this class happens during the static constructor when we compile a small piece of JScript.NET code. Once we have the code compiled we can reach inside the assembly and create an instance of the evaluation class. Since a static constructor will execute only once – your application will only perform this work the first time execution references a static member of the class.

With an object instance in hand, we use InvokeMember to dynamically invoke the method to perform evaluation. Links in the resources section will provide more information.

Update: Be careful using dynamic execution. There is always the risk of a code injection attack, particularly if the input comes from an untrusted source.

 

using System;
using System.CodeDom.Compiler;
using System.Reflection;
using Microsoft.JScript;

namespace OdeToCode.Utility
{
   public class Evaluator
   {
      public static int EvalToInteger(string statement)
      {
         string s = EvalToString(statement);
         return int.Parse(s.ToString());
      }

      public static double EvalToDouble(string statement)
      {
         string s = EvalToString(statement);
         return double.Parse(s);
      }

      public static string EvalToString(string statement)
      {
         object o = EvalToObject(statement);
         return o.ToString();
      }

      public static object EvalToObject(string statement)
      {
         return _evaluatorType.InvokeMember(
                     "Eval", 
                     BindingFlags.InvokeMethod, 
                     null, 
                     _evaluator, 
                     new object[] { statement } 
                  );
      }
               
      static Evaluator()
      {
         ICodeCompiler compiler;
         compiler = new JScriptCodeProvider().CreateCompiler();

         CompilerParameters parameters;
         parameters = new CompilerParameters();
         parameters.GenerateInMemory = true;
         
         CompilerResults results;
         results = compiler.CompileAssemblyFromSource(parameters, _jscriptSource);

         Assembly assembly = results.CompiledAssembly;
         _evaluatorType = assembly.GetType("Evaluator.Evaluator");
         
         _evaluator = Activator.CreateInstance(_evaluatorType);
      }
      
      private static object _evaluator = null;
      private static Type _evaluatorType = null;
      private static readonly string _jscriptSource = 
         
          @"package Evaluator
            {
               class Evaluator
               {
                  public function Eval(expr : String) : String 
                  { 
                     return eval(expr); 
                  }
               }
            }";
   }
}

by K. Scott Allen

Resources

.NET Framework Developer’s Guide : Using the CodeDOM

HOWTO: Programmatically Compile Code Using C# Compiler

Dynamically Loading and Using Types