【问题标题】:calculate result from a string expression dynamically动态计算字符串表达式的结果
【发布时间】:2012-09-14 20:07:21
【问题描述】:

有没有办法计算字符串表达式的结果,例如 mystring = "2*a+32-Math.Sin(6)" 动态知道 a 是我拥有的变量,可能有一些动态解决方案或使用 System.Reflection

string mystring = "2*a+32-Math.Sin(6)"`;
decimal result = SomeMethod(mystring,3); // where a = 3 for example

【问题讨论】:

    标签: c#


    【解决方案1】:

    让javascript计算你的表达式怎么样?

    Type scriptType = Type.GetTypeFromCLSID(Guid.Parse("0E59F1D5-1FBE-11D0-8FF2-00A0D10038BC"));
    
    dynamic obj = Activator.CreateInstance(scriptType, false);
    obj.Language = "javascript";
    
    var res = obj.Eval("a=3; 2*a+32-Math.sin(6)");
    

    【讨论】:

    • 什么是指导,有没有办法避免这种情况
    • 我们可以在 .net 和 msscript COM 之间使用互操作吗?没有那个 GUID
    • @SéddikLaraba 不,我不这么认为。你为什么不想使用那个指南?它有什么问题?
    • @SéddikLaraba 引用 COM 对象或使用 CLSID 创建,都是平等的。使用任何你想要的。
    • 我已将 msscript.ocx 添加到我的参考文献中,效果很好,谢谢!!
    【解决方案2】:

    如果发现它运行良好,抱歉打扰,我想要的只是运行中的编译器。 &这就是我得到的

    MessageBox.Show(Eval("5*3-Math.Sin(12) + 25*Math.Pow(3,2)").ToString());
    
    public static object Eval(string sCSCode)
        {
    
            CodeDomProvider icc = CodeDomProvider.CreateProvider("C#");
            CompilerParameters cp = new CompilerParameters();
    
            cp.ReferencedAssemblies.Add("system.dll");
            cp.ReferencedAssemblies.Add("system.xml.dll");
            cp.ReferencedAssemblies.Add("system.data.dll");
            cp.ReferencedAssemblies.Add("system.windows.forms.dll");
            cp.ReferencedAssemblies.Add("system.drawing.dll");
    
            cp.CompilerOptions = "/t:library";
            cp.GenerateInMemory = true;
    
            StringBuilder sb = new StringBuilder("");
            sb.Append("using System;\n");
            sb.Append("using System.Xml;\n");
            sb.Append("using System.Data;\n");
            sb.Append("using System.Data.SqlClient;\n");
            sb.Append("using System.Windows.Forms;\n");
            sb.Append("using System.Drawing;\n");
    
            sb.Append("namespace CSCodeEvaler{ \n");
            sb.Append("public class CSCodeEvaler{ \n");
            sb.Append("public object EvalCode(){\n");
            sb.Append("return " + sCSCode + "; \n");
            sb.Append("} \n");
            sb.Append("} \n");
            sb.Append("}\n");
    
            CompilerResults cr = icc.CompileAssemblyFromSource(cp, sb.ToString());
            if (cr.Errors.Count > 0)
            {
                MessageBox.Show("ERROR: " + cr.Errors[0].ErrorText,
                   "Error evaluating cs code", MessageBoxButton.OK,
                   MessageBoxImage.Error);
                return null;
            }
    
            System.Reflection.Assembly a = cr.CompiledAssembly;
            object o = a.CreateInstance("CSCodeEvaler.CSCodeEvaler");
    
            Type t = o.GetType();
            System.Reflection.MethodInfo mi = t.GetMethod("EvalCode");
    
            object s = mi.Invoke(o, null);
            return s;
    
        }
    

    【讨论】:

    • 是否每次sCSCode 更改时都创建一个新程序集(内部将使用csc)?只需创建一个循环并查看性能。
    • 有那么糟糕吗,因为我想尽可能使用.Net内部方法,如果太贵,我会采用javascript解决方案
    • 可以存储带有实例的对象o以获得更好的性能并稍后调用
    【解决方案3】:

    您可以通过以下方式在SomeMethod 中使用Compute 数据表的methood:

           static decimal Somemethod(int val)
            {
                var result = (decimal)new DataTable().Compute(string.Format("2*{0}+32-{1}", val, Math.Sin(6)), "");
                return result;
            }
    

    简单地说,你可以这样调用:

            result = Somemethod(3);
    

    【讨论】:

      【解决方案4】:

      以下是我所知道的在 C# 中动态评估字符串表达式的一些最流行的方法。

      微软解决方案

      非微软解决方案(不是说有什么问题)

      【讨论】:

        【解决方案5】:

        我认为您所要求的内容没有任何本地支持,但是有很多方法可以实现它,其中没有一种是完全微不足道的,但我认为它们很容易:

        【讨论】:

          【解决方案6】:

          使用您要用于评估表达式的方法制作抽象类。在运行时创建一个继承该类的新类。我会尽快分享代码。

          这里承诺的是代码:

              public class BaseClass
              {
              public BaseClass(){}
              public virtual double Eval(double x,double y){return 0;}
          }
          public class MathExpressionParser
          {
              private BaseClass Evalulator=null;
              public MathExpressionParser(){}
              public bool Intialize(string equation)
              {
                  Microsoft.CSharp.CSharpCodeProvider cp=new Microsoft.CSharp.CSharpCodeProvider();
                  System.CodeDom.Compiler.ICodeCompiler comp=cp.CreateCompiler();
                  System.CodeDom.Compiler.CompilerParameters cpar=new CompilerParameters();
          
                  cpar.GenerateInMemory=true;
                  cpar.GenerateExecutable=false;
                  cpar.ReferencedAssemblies.Add("system.dll");
                  cpar.ReferencedAssemblies.Add("EquationsParser.exe");   //Did you see this before;
          
                  string sourceCode="using System;"+
                                    "class DrivedEval:EquationsParser.BaseClass" +
                                    "{"+   
                                            "public DrivedEval(){}"+
                                            "public override double Eval(double x,double y)"+
                                            "{"+
                                                  "return "+ /*Looook here code insertion*/ equation +";"+
                                            "}"+
                                    "}";
                  //the previouse source code will be compiled now(run time);
                  CompilerResults result=comp.CompileAssemblyFromSource(cpar,sourceCode);
          
                  //If there are error in the code display it for the programmer who enter the equation
                  string errors="";
                  foreach(CompilerError rrr in result.Errors)
                  {
                      if(rrr.IsWarning)
                          continue;
                      errors+="\n"+rrr.ErrorText;
                      errors+="\n"+rrr.ToString();
                  }
                  //You Can show error if there in the sourceCode you just compiled uncomment the following
                  //MessageBox.Show(errors);
                  if(result.Errors.Count==0&&result.CompiledAssembly!=null)
                  {
                      Type objtype=result.CompiledAssembly.GetType("DrivedEval");
                      try
                      {
                          if(objtype!=null)
                          {
                              Evalulator=(BaseClass)Activator.CreateInstance(objtype);
                          }
                      }
                      catch(Exception ex)
                      {
                          MessageBox.Show(ex.Message,"Error in Creation the object");
                      }
                      return true;
                  }
                  else return false;
              }
              public double evaluate(double x,double y)
              {
                  if(Evalulator==null)
                      return 0.0;
                  return this.Evalulator.Eval(x,y);
              }
          }
          

          您需要进行以下简单测试以确保其正常工作:

          private void button1_Click(object sender, System.EventArgs e)
          {
          
              if(parser.Intialize(textBox1.Text)==false)
          {
              MessageBox.Show("Check equation");
              return;
          }
          textBox4.Text=(parser.evaluate(double.Parse(textBox2.Text),double.Parse(textBox3.Text))).ToString();
          }
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2015-12-03
            相关资源
            最近更新 更多