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#語法的數學表達式計算。
