C#动态编译计算表达式的值,是通过System.CodeDom.Compiler命名空间下的相关类来实现的。其步骤大致为:
1.将表达式包装成为可编译的C#代码
2.使用反射调用上一步编译的代码。
示例如下:在界面上放一个TextBox,用来输入表达式;放一个按钮,用来相应用户点击,以进行表达式的计算;在另外一个TextBox中显示计算结果。对应的xaml代码如下:
<Window x:Class="SampleCodeDemo.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" Height="403" Width="663" Loaded="Window_Loaded"> <Grid> <TextBox Height="87" HorizontalAlignment="Left" Margin="12,12,0,0" Name="txtExpression" VerticalAlignment="Top" Width="617" TextWrapping="Wrap" /> <Button Content="计算" Height="23" HorizontalAlignment="Left" Margin="554,114,0,0" Name="btnCalculate" VerticalAlignment="Top" Width="75" Click="btnCalculate_Click" /> <TextBox Height="48" HorizontalAlignment="Left" Margin="12,157,0,0" Name="txtResult" VerticalAlignment="Top" Width="617" IsEnabled="False" TextWrapping="Wrap" /> </Grid> </Window>
在后台代码中,首先添加一下引用:
using Microsoft.CSharp; using System.CodeDom.Compiler; using System.Reflection;
剩余的代码如下:
private void Window_Loaded(object sender, RoutedEventArgs e) { this.txtExpression.Focus(); } private void btnCalculate_Click(object sender, RoutedEventArgs e) { try { string expression = this.txtExpression.Text.Trim(); this.txtResult.Text = this.ComplierCode(expression).ToString(); } catch (Exception ex) { this.txtResult.Text = ex.Message; } } private object ComplierCode(string expression) { string code = WrapExpression(expression); CSharpCodeProvider csharpCodeProvider = new CSharpCodeProvider(); //编译的参数 CompilerParameters compilerParameters = new CompilerParameters(); //compilerParameters.ReferencedAssemblies.AddRange(); compilerParameters.CompilerOptions = "/t:library"; compilerParameters.GenerateInMemory = true; //开始编译 CompilerResults compilerResults = csharpCodeProvider.CompileAssemblyFromSource(compilerParameters, code); if (compilerResults.Errors.Count > 0) throw new Exception("编译出错!"); Assembly assembly = compilerResults.CompiledAssembly; Type type = assembly.GetType("ExpressionCalculate"); MethodInfo method = type.GetMethod("Calculate"); return method.Invoke(null, null); } private string WrapExpression(string expression) { string code = @" using System; class ExpressionCalculate { public static DateTime start_dt = Convert.ToDateTime(""{start_dt}""); public static DateTime end_dt = Convert.ToDateTime(""{end_dt}""); public static DateTime current_dt = DateTime.Now; public static object Calculate() { return {0}; } } "; return code.Replace("{0}", expression); }
简单的说明一下,WrapExpression方法用来包装表达式,使其可以被代码编译器编译通过。ComplierCode方法用来编译,并通过反射执行代码。其它是两个事件的处理方法,无需多说。
在上面的示例中可以实现动态计算符合C#语法的数学表达式计算。