C#动态编译计算表达式的值

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#语法的数学表达式计算。

 

posted @ 2012-12-17 18:08  拓荒者FF  阅读(5568)  评论(0编辑  收藏  举报