Title: Evaluate numeric expressions that are entered by the user in C#
This example shows one way to evaluate mathematical expressions entered by the user at runtime.
Enter a numeric expression involving x and y in the upper text box. Then enter values for x and y in the lower text boxes and press the Evaluate button to make the program evalulate the expression.
The program executes the following code when you click the Evaluate button.
// Evaluate the expression.
private void btnEvaluate_Click(object sender, EventArgs e)
{
// Turn the equation into a function.
string function_text =
"public static class Evaluator" +
"{" +
" public static double Evaluate(double x, double y)" +
" {" +
" return " + txtExpression.Text + ";" +
" }" +
"}";
// Compile the function.
CodeDomProvider code_provider =
CodeDomProvider.CreateProvider("C#");
// Generate a non-executable assembly in memory.
CompilerParameters parameters = new CompilerParameters();
parameters.GenerateInMemory = true;
parameters.GenerateExecutable = false;
// Compile the code.
CompilerResults results =
code_provider.CompileAssemblyFromSource(parameters,
function_text);
// If there are errors, display them.
if (results.Errors.Count > 0)
{
string msg = "Error compiling the expression.";
foreach (CompilerError compiler_error in results.Errors)
{
msg += "\n" + compiler_error.ErrorText;
}
MessageBox.Show(msg, "Expression Error",
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
else
{
// Get the Evaluator class type.
Type evaluator_type =
results.CompiledAssembly.GetType("Evaluator");
// Get a MethodInfo object describing the Evaluate method.
MethodInfo method_info =
evaluator_type.GetMethod("Evaluate");
// Make the parameter list.
object[] method_params = new object[]
{
double.Parse(txtX.Text),
double.Parse(txtY.Text)
};
// Execute the method.
double expression_result =
(double)method_info.Invoke(null, method_params);
// Display the returned result.
txtResult.Text = expression_result.ToString();
}
}
The code first composes a class that includes a single function containing the expression entered by the user. The result looks something like this:
public static class Evaluator
{
public static double Evaluate(double x, double y)
{
return 2 * x + 4 * y + x * y;
}
}
The actual string has the class and its function all on one line of text. I've added line breaks here to make it more readable but the compiler doesn't care.
Next the code creates a CodeDomProvider to compile C# code. It uses parameters to tell the provider to create a non-executable assembly built in memory, and then it calls the CompileAssemblyFromSource method to compile the Evaluator class with its Evaluate function.
If there are errors, the program displays them. Try adding some syntax errors to the equation to see what happens. If the error isn't too extreme, the error messages are often good enough to let you fix the problem.
The code then gets a Type representing the Evaluator class and from that gets a MethodInfo object representing the class's Evaluate method. The program makes a parameter array that holds the values of x and y to pass into the method and invokes the method, passing it those parameters. The program converts the method's return result from a generic object into a double and displays it.
This method is not blindingly fast because it takes a little while to compile the Evaluator class. Once the class is compiled, however, calling it is fairly quick. That means you could evaluate the same function for many different values of x and y relatively quickly by compiling the class once and then invoking it many times.
Download the example to experiment with it and to see additional details.
|