Evaluate expression using Reflection

Using Reflection we can evaluate an expression where value of the variables in the expression and even expression too are not known, in fact are generated dynamically at runtime. For e.g. I have an expression that can be sum of value of X and Y for one row and product of value of X and Y for the second row. So here my expression is also dynamic and values are also dynamic. I can use reflection to evaluate resultant for such processes.

Reflection basically is used when you don’t know what your code will return at the runtime (i.e. X + Y or X * Y) but it generates assemblies at runtime and also calls them at runtime and gives you the resultant.

First of all we need to add the reference to reflection in our declaration section.

using System.Reflection;

Now we create an object of c# code provider class, which has the method “CreateCompiler” to create compiler at runtime returning an object of “ICodeCompiler”.

Microsoft.CSharp.CSharpCodeProvider cp

= new Microsoft.CSharp.CSharpCodeProvider();
System.CodeDom.Compiler.ICodeCompiler ic = cp.CreateCompiler();

Now we will create an object of CompilerParameters, which provides us the functionality to add referenced assemblies at runtime.

System.CodeDom.Compiler.CompilerParameters cpar =
new System.CodeDom.Compiler.CompilerParameters();
cpar.GenerateInMemory = true;
cpar.GenerateExecutable = false;
cpar.ReferencedAssemblies.Add("system.dll");

Define the code to evaluate your expression in a string as shown below. The “strExpression” is the expression you can pass to this method which can be (X + Y) or (X * Y)

string src = "using System;" +
"class myclass" +
"{" +
"public myclass(){}" +
"public double eval(double X, double Y)" +
"{" +
"return " + textBox1.Text + ";" +
"}" +
"}";

Create an object of CompilerResults and call the method “CompileAssemblyFromSource” of ICodeCompiler which takes CompilerParameters and the string of your assembly (which is generated at runtime) as arguments.

System.CodeDom.Compiler.CompilerResults cr = ic.CompileAssemblyFromSource(cpar, src);

Now you can go through the loop of CompilerError object of CompilerResults to fetch errors, if any present in the resultant of the assembly you executed at runtime. Display the error in message box.

foreach (System.CodeDom.Compiler.CompilerError ce in cr.Errors)

{
MessageBox.Show(ce.ErrorText);
return;
}

If there are no error in the CompilerResults object then we can fetch the Type of newly created assembly (which is created at runtime). Fetch the MethodInfo object using “GetMethod” method of Type object. We can fetch the resultant value by creating the instance of Type object using Invoke method.

if (cr.Errors.Count == 0 && cr.CompiledAssembly != null)
{
Type ObjType = cr.CompiledAssembly.GetType("myclass");
MethodInfo info = ObjType.GetMethod("eval");
object value = info.Invoke(Activator.CreateInstance(ObjType),
new object[] { Convert.ToDouble(txtX.Text),
Convert.ToDouble(txtY.Text) });
MessageBox.Show(value.ToString());
}

Thus to fetch a expression value at runtime where expression values and operators are dynamic can be achieved using reflection.

The only drawback of using reflection is that it degrades the performance by 400% compared to early binding. So we should use runtime assemblies only when we do not have the possibility of early binding in the process.

 

Leave a reply