最近用到了这个功能,要计算一些字符串表达式,如"1 + 3 / 2"等等,就写了这个类。原理很简单,就是用CodeDom动态生成一个包含自定义函数的程序集,再通过反射调用。网上例子极多。我这个类是拿来就可以用的,只需要Copy一下代码就可以直接用,不用读代码。支持常用数学函数,如Sin,Log等,而且不区分大小写。
using System; using System.Collections.Generic; using System.Text; using System.CodeDom.Compiler; using Microsoft.VisualBasic; using System.Reflection; namespace Ninputer.Utilities { sealed class Evaluator { private static CodeDomProvider comp = new VBCodeProvider(); private static CompilerParameters cp = new CompilerParameters(); private static MethodInfo mi; public static object Eval(string expression) { StringBuilder codeBuilder = new StringBuilder(); codeBuilder.AppendLine("Imports System"); codeBuilder.AppendLine("Imports System.Math"); codeBuilder.AppendLine("Imports Microsoft.VisualBasic"); codeBuilder.AppendLine(); codeBuilder.AppendLine("Public Module Mode"); codeBuilder.AppendLine(" Public Function Func() As Object"); codeBuilder.AppendLine(" Return " + expression); codeBuilder.AppendLine(" End Function"); codeBuilder.AppendLine("End Module"); cp.ReferencedAssemblies.Add("System.dll"); cp.ReferencedAssemblies.Add("Microsoft.VisualBasic.dll"); cp.GenerateExecutable = false; cp.GenerateInMemory = true; string code = codeBuilder.ToString(); CompilerResults cr = comp.CompileAssemblyFromSource(cp, code); if (cr.Errors.HasErrors) { return null; } else { Assembly a = cr.CompiledAssembly; Type t = a.GetType("Mode"); //object mode = a.CreateInstance("Mode"); mi = t.GetMethod("Func", BindingFlags.Static | BindingFlags.Public); return mi.Invoke(null, new object[0]); } } } }
用法也非常简单,实际上除了数学表达式,任何含字面量的有效VB表达式都可以执行。
class Program{ static void Main(string[] args) { double a = (double)Evaluator.Eval("sin(0.2) + 5"); Console.WriteLine(a.ToString()); } }
注意,我使用的是.NET 2.0的语法,使用.NET 1.1 / VS.NET 2003的请用这段代码: