none
如何计算字符串中表达式的值? RRS feed

  • 问题

  • 如何一个字符串变量存储着一个数学表达式(可能是动态变化的,比如是由用户输入的),如何用C#计算出它的值?
    不要告诉我自行分析表达式,一定存在系统内置的方法。
    2009年11月27日 5:23

答案

  • 你好!
         .NET提供了CSharpCodeProvider类,可以动态的编译用户输入的代码,如果你要计算用户输入的数学表达式,只要构造相应的代码段就可以了,例如用户输入1+1等,你把这个"1+1"存储在一个String变量s中,然后在把这个s加到GenerateCode方法中构造代码,就实现计算用户输入数字表达式了,参考如下例子:
    using System;
    using System.Reflection;
    using System.Globalization;
    using Microsoft.CSharp;
    using System.CodeDom;
    using System.CodeDom.Compiler;
    using System.Text;
    
    namespace ConsoleApplication1
    {
        public class Program
          {
            static void Main(string[] args)
              {
                // 1.CSharpCodePrivoder
                  CSharpCodeProvider objCSharpCodePrivoder = new CSharpCodeProvider();
    
                // 2.ICodeComplier
                  ICodeCompiler objICodeCompiler = objCSharpCodePrivoder.CreateCompiler();
    
                // 3.CompilerParameters
                  CompilerParameters objCompilerParameters = new CompilerParameters();
                  objCompilerParameters.ReferencedAssemblies.Add("System.dll");
                  objCompilerParameters.GenerateExecutable = false;
                  objCompilerParameters.GenerateInMemory = true;
    
                // 4.CompilerResults
                  CompilerResults cr = objICodeCompiler.CompileAssemblyFromSource(objCompilerParameters, GenerateCode());
    
                if (cr.Errors.HasErrors)
                  {
                      Console.WriteLine("编译错误:");
                    foreach (CompilerError err in cr.Errors)
                      {
                          Console.WriteLine(err.ErrorText);
                      }
                  }
                else
                  {
                    // 通过反射,调用HelloWorld的实例
                      Assembly objAssembly = cr.CompiledAssembly;
                    object objHelloWorld = objAssembly.CreateInstance("DynamicCodeGenerate.HelloWorld");
                      MethodInfo objMI = objHelloWorld.GetType().GetMethod("OutPut");
    
                      Console.WriteLine(objMI.Invoke(objHelloWorld, null));
                  }
    
                  Console.ReadLine();
              }
    
            static string GenerateCode()
              {
                  StringBuilder sb = new StringBuilder();
                  sb.Append("using System;");
                  sb.Append(Environment.NewLine);
                  sb.Append("namespace DynamicCodeGenerate");
                  sb.Append(Environment.NewLine);
                  sb.Append("{");
                  sb.Append(Environment.NewLine);
                  sb.Append("      public class HelloWorld");
                  sb.Append(Environment.NewLine);
                  sb.Append("      {");
                  sb.Append(Environment.NewLine);
                  sb.Append("          public string OutPut()");
                  sb.Append(Environment.NewLine);
                  sb.Append("          {");
                  sb.Append(Environment.NewLine);
                  sb.Append("               return \"Hello world!\";");
                  sb.Append(Environment.NewLine);
                  sb.Append("          }");
                  sb.Append(Environment.NewLine);
                  sb.Append("      }");
                  sb.Append(Environment.NewLine);
                  sb.Append("}");
    
                string code = sb.ToString();
                  Console.WriteLine(code);
                  Console.WriteLine();
    
                return code;
              }
          }
    }

    周雪峰
    • 已标记为答案 062369 2009年11月27日 13:04
    2009年11月27日 7:25
    版主

全部回复

  • 看来LZ是被 封装  宠坏了~~~~

    与其学会只用封装好的东西

    不如去探求里面封装了什么东西  人家是怎么实现你要的功能的

    靠皮毛的技术是站不稳脚跟的

    2009年11月27日 6:14
  • 你好!
         .NET提供了CSharpCodeProvider类,可以动态的编译用户输入的代码,如果你要计算用户输入的数学表达式,只要构造相应的代码段就可以了,例如用户输入1+1等,你把这个"1+1"存储在一个String变量s中,然后在把这个s加到GenerateCode方法中构造代码,就实现计算用户输入数字表达式了,参考如下例子:
    using System;
    using System.Reflection;
    using System.Globalization;
    using Microsoft.CSharp;
    using System.CodeDom;
    using System.CodeDom.Compiler;
    using System.Text;
    
    namespace ConsoleApplication1
    {
        public class Program
          {
            static void Main(string[] args)
              {
                // 1.CSharpCodePrivoder
                  CSharpCodeProvider objCSharpCodePrivoder = new CSharpCodeProvider();
    
                // 2.ICodeComplier
                  ICodeCompiler objICodeCompiler = objCSharpCodePrivoder.CreateCompiler();
    
                // 3.CompilerParameters
                  CompilerParameters objCompilerParameters = new CompilerParameters();
                  objCompilerParameters.ReferencedAssemblies.Add("System.dll");
                  objCompilerParameters.GenerateExecutable = false;
                  objCompilerParameters.GenerateInMemory = true;
    
                // 4.CompilerResults
                  CompilerResults cr = objICodeCompiler.CompileAssemblyFromSource(objCompilerParameters, GenerateCode());
    
                if (cr.Errors.HasErrors)
                  {
                      Console.WriteLine("编译错误:");
                    foreach (CompilerError err in cr.Errors)
                      {
                          Console.WriteLine(err.ErrorText);
                      }
                  }
                else
                  {
                    // 通过反射,调用HelloWorld的实例
                      Assembly objAssembly = cr.CompiledAssembly;
                    object objHelloWorld = objAssembly.CreateInstance("DynamicCodeGenerate.HelloWorld");
                      MethodInfo objMI = objHelloWorld.GetType().GetMethod("OutPut");
    
                      Console.WriteLine(objMI.Invoke(objHelloWorld, null));
                  }
    
                  Console.ReadLine();
              }
    
            static string GenerateCode()
              {
                  StringBuilder sb = new StringBuilder();
                  sb.Append("using System;");
                  sb.Append(Environment.NewLine);
                  sb.Append("namespace DynamicCodeGenerate");
                  sb.Append(Environment.NewLine);
                  sb.Append("{");
                  sb.Append(Environment.NewLine);
                  sb.Append("      public class HelloWorld");
                  sb.Append(Environment.NewLine);
                  sb.Append("      {");
                  sb.Append(Environment.NewLine);
                  sb.Append("          public string OutPut()");
                  sb.Append(Environment.NewLine);
                  sb.Append("          {");
                  sb.Append(Environment.NewLine);
                  sb.Append("               return \"Hello world!\";");
                  sb.Append(Environment.NewLine);
                  sb.Append("          }");
                  sb.Append(Environment.NewLine);
                  sb.Append("      }");
                  sb.Append(Environment.NewLine);
                  sb.Append("}");
    
                string code = sb.ToString();
                  Console.WriteLine(code);
                  Console.WriteLine();
    
                return code;
              }
          }
    }

    周雪峰
    • 已标记为答案 062369 2009年11月27日 13:04
    2009年11月27日 7:25
    版主
  • 一个比较临时的方法是让数据库来做这个,例:SELECT 5+3 AS result FROM dual;
    2009年11月27日 7:37
  • 直接用JScript中的Eval方法更方便,编译成dll后 C#中直接引用
    参考我这篇文章 http://hi.baidu.com/1987raymond/blog/item/4bf39d449f187488b2b7dc01.html
    Wenn ich dich hab’,gibt es nichts, was unerträglich ist.坚持不懈!My blog~~~
    2009年11月27日 9:43
    版主
  • 看来LZ是被 封装  宠坏了~~~~

    与其学会只用封装好的东西

    不如去探求里面封装了什么东西  人家是怎么实现你要的功能的

    靠皮毛的技术是站不稳脚跟的


    也许你说的对,但你似乎误会我了。
    我只是不想重复发明轮子。
    2009年11月27日 13:03
  • 直接用JScript中的Eval方法更方便,编译成dll后 C#中直接引用
    参考我这篇文章 http://hi.baidu.com/1987raymond/blog/item/4bf39d449f187488b2b7dc01.html
    Wenn ich dich hab’,gibt es nichts, was unerträglich ist.坚持不懈!My blog~~~

    好像微软已经不推荐使用这个方法了,后续版本可能不支持。
    2009年11月27日 13:06
  • 一个比较临时的方法是让数据库来做这个,例:SELECT 5+3 AS result FROM dual;

    是个好办法。
    2009年11月27日 13:06
  • 谢谢您的解答。
    2009年11月27日 13:15