动态计算字符串表达式的结果

有没有办法计算字符串表达式的结果,例如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 

如何让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)"); 

您可以通过以下方式在SomeMethod中使用数据表的计算方法:

  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); 

如果发现它的工作完美,抱歉打扰,我想要的就是动态编译器。 这就是我得到的

 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; } 

我不认为有任何本地支持你所要求的,但是有很多方法可以实现它,其中没有一个是完全无关紧要的,但按照我认为它们很简单的顺序:

  • 利用您希望的表达支持的嵌入式语言。 例如铁ruby: http : //ironruby.codeplex.com/

  • 使用程序中的C#编译器,如LINQPad如何编译代码? 。

  • 用讽刺的东西写自己的解析: http : //irony.codeplex.com/

  • 解析后,您可以使用表达式树来获得结果: http : //msdn.microsoft.com/en-us/library/bb397951.aspx

使用要用于评估表达式的方法创建抽象类。 在运行时创建一个inheritance该类的新类。 我将很快分享这些代码。

正如这里所承诺的那样是代码:

  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(); } 

以下是我在C#中动态评估字符串表达式时最常用的一些方法。

Microsoft解决方案

  • C#CodeDomCodeProvider :
    • 请参阅LINQ如何工作以及此CodeProject文章
  • 罗斯林 :
    • 请参阅有关Rosly Emit API和此StackOverflow答案的这篇文章
  • DataTable.Compute :
    • 在StackOverflow上查看此答案
  • Webbrowser.Document.InvokeScript
    • 请参阅此StackOverflow问题
  • 的DataBinder.Eval
  • ScriptControl的
    • 请参阅StackOverflow上的这个答案和这个问题

非Microsoft解决方案(并不是说有什么问题)

  • 表达评估库:
    • 逃跑
    • DynamicExpresso
    • NCalc
  • 滚动你自己的语言构建工具包,如:
    • 讽刺
    • 拼图