Ok, I searched around quite a bit for something that could do simple math expressions, and found a few complicated examples that utilised the CodeDom namespace in the .NET framework to let C# do all the work for us. This function allows you to execute any C# code on the fly with slight modification, but for this purpose, it's primary function is as a calculator. I put this up here because all of the examples I found were quite lengthy and typically contained alot more code than I needed for this simple task.
To start, you need to either import the following namespaces, or fully qualify several of the variable declarations and method usages in the function. I think it's much cleaner to just import the namespaces:
VB Code:
using System.CodeDom.Compiler; using Microsoft.CSharp; using System.Reflection;
Now that you have the namespaces imported into your project, the following function will solve almost all mathematical expressions (Basically anything you could solve in a single line of code)
VB Code:
/// <summary> /// A simple function to get the result of a C# expression (basic and advanced math possible) /// </summary> /// <param name="command">String value containing an expression that can evaluate to a double.</param> /// <returns>a Double value after evaluating the command string.</returns> private double ProcessCommand(string command) { //Create a C# Code Provider CSharpCodeProvider myCodeProvider = new CSharpCodeProvider(); // Build the parameters for source compilation. CompilerParameters cp = new CompilerParameters(); cp.GenerateExecutable = false;//No need to make an EXE file here. cp.GenerateInMemory = true; //But we do need one in memory. cp.OutputAssembly = "TempModule"; //This is not necessary, however, if used repeatedly, causes the CLR to not need to //load a new assembly each time the function is run. //The below string is basically the shell of a C# program, that does nothing, but contains an //Evaluate() method for our purposes. I realize this leaves the app open to injection attacks, //But this is a simple demonstration. string TempModuleSource = "namespace ns{" + "using System;" + "class class1{" + "public static double Evaluate(){return " + command + ";}}} "; //Our actual Expression evaluator CompilerResults cr = myCodeProvider.CompileAssemblyFromSource(cp,TempModuleSource); if (cr.Errors.Count > 0) { //If a compiler error is generated, we will throw an exception because //the syntax was wrong - again, this is left up to the implementer to verify syntax before //calling the function. The calling code could trap this in a try loop, and notify a user //the command was not understood, for example. throw new ArgumentException("Expression cannot be evaluated, please use a valid C# expression"); } else { MethodInfo Methinfo = cr.CompiledAssembly.GetType("ns.class1").GetMethod("Evaluate"); return (double)Methinfo.Invoke(null, null); } }
It is a little on the slow side, but does work. Any suggestions on how to speed up the process are encouraged.
Here are some sample calls to the function and their outputs:
VB Code:
Console.WriteLine(ProcessCommand("1+1").ToString()); //Displays 2 Console.WriteLine(ProcessCommand("Math.PI").ToString()); //Displays 3.14159265358979 Console.WriteLine(ProcessCommand("Math.Abs(-22)").ToString()); //Displays 22 Console.WriteLine(ProcessCommand("3-4+6+7+22/3+66*(55)").ToString()); //Displays 3649
I will put a VB.NET version up later this week if anyone thinks it could be usefull.
Bill




Reply With Quote