原文地址:http://blog.csdn.net/qwlovedzm/article/details/6292147
近日有个项目有不少的计算公式,而且要求能定制,如何能将字符串或表达式直接转为C#的可执行代码就好了。
经过从网上查阅资料,发现有一个开源的工具类,将它修改后改为如下效果:
- using System;
- using System.Data;
- using System.Configuration;
- using System.Text;
- using System.CodeDom.Compiler;
- using Microsoft.CSharp;
- using System.Reflection;
- namespace SSEC.Math
- {
- /// <summary>
- /// 本类用来将字符串转为可执行文本并执行
- /// </summary>
- publicclass MyEvaluator
- {
- #region 构造函数
- /// <summary>
- /// 可执行串的构造函数
- /// </summary>
- /// <param name="items">
- /// 可执行字符串数组
- /// </param>
- public MyEvaluator(EvaluatorItem[] items)
- {
- ConstructEvaluator(items); //调用解析字符串构造函数进行解析
- }
- /// <summary>
- /// 可执行串的构造函数
- /// </summary>
- /// <param name="returnType">返回值类型</param>
- /// <param name="expression">执行表达式</param>
- /// <param name="name">执行字符串名称</param>
- public MyEvaluator(Type returnType, string expression, string name)
- {
- //创建可执行字符串数组
- EvaluatorItem[] items = { new EvaluatorItem(returnType, expression, name) };
- ConstructEvaluator(items); //调用解析字符串构造函数进行解析
- }
- /// <summary>
- /// 可执行串的构造函数
- /// </summary>
- /// <param name="item">可执行字符串项</param>
- public MyEvaluator(EvaluatorItem item)
- {
- EvaluatorItem[] items = { item };//将可执行字符串项转为可执行字符串项数组
- ConstructEvaluator(items); //调用解析字符串构造函数进行解析
- }
- /// <summary>
- /// 解析字符串构造函数
- /// </summary>
- /// <param name="items">待解析字符串数组</param>
- privatevoid ConstructEvaluator(EvaluatorItem[] items)
- {
- //创建C#编译器实例
- CodeDomProvider provider = CodeDomProvider.CreateProvider("C#");
- //过时了
- //ICodeCompiler comp = provider.CreateCompiler();
- //编译器的传入参数
- CompilerParameters cp = new CompilerParameters();
- cp.ReferencedAssemblies.Add("system.dll"); //添加程序集 system.dll 的引用
- cp.ReferencedAssemblies.Add("system.data.dll"); //添加程序集 system.data.dll 的引用
- cp.ReferencedAssemblies.Add("system.xml.dll"); //添加程序集 system.xml.dll 的引用
- cp.GenerateExecutable = false; //不生成可执行文件
- cp.GenerateInMemory = true; //在内存中运行
- StringBuilder code = new StringBuilder(); //创建代码串
- /*
- * 添加常见且必须的引用字符串
- */
- code.Append("using System; /n");
- code.Append("using System.Data; /n");
- code.Append("using System.Data.SqlClient; /n");
- code.Append("using System.Data.OleDb; /n");
- code.Append("using System.Xml; /n");
- code.Append("namespace SSEC.Math { /n"); //生成代码的命名空间为EvalGuy,和本代码一样
- code.Append(" public class _Evaluator { /n"); //产生 _Evaluator 类,所有可执行代码均在此类中运行
- foreach (EvaluatorItem item in items) //遍历每一个可执行字符串项
- {
- code.AppendFormat(" public {0} {1}() ", //添加定义公共函数代码
- item.ReturnType.Name, //函数返回值为可执行字符串项中定义的返回值类型
- item.Name); //函数名称为可执行字符串项中定义的执行字符串名称
- code.Append("{ "); //添加函数开始括号
- code.AppendFormat("return ({0});", item.Expression);//添加函数体,返回可执行字符串项中定义的表达式的值
- code.Append("}/n"); //添加函数结束括号
- }
- code.Append("} }"); //添加类结束和命名空间结束括号
- //得到编译器实例的返回结果
- CompilerResults cr = provider.CompileAssemblyFromSource(cp, code.ToString());//comp
- if (cr.Errors.HasErrors) //如果有错误
- {
- StringBuilder error = new StringBuilder(); //创建错误信息字符串
- error.Append("编译有错误的表达式: "); //添加错误文本
- foreach (CompilerError err in cr.Errors) //遍历每一个出现的编译错误
- {
- error.AppendFormat("{0}/n", err.ErrorText); //添加进错误文本,每个错误后换行
- }
- thrownew Exception("编译错误: " + error.ToString());//抛出异常
- }
- Assembly a = cr.CompiledAssembly; //获取编译器实例的程序集
- _Compiled = a.CreateInstance("SSEC.Math._Evaluator"); //通过程序集查找并声明 SSEC.Math._Evaluator 的实例
- }
- #endregion
- #region 公有成员
- /// <summary>
- /// 执行字符串并返回整型值
- /// </summary>
- /// <param name="name">执行字符串名称</param>
- /// <returns>执行结果</returns>
- publicint EvaluateInt(string name)
- {
- return (int)Evaluate(name);
- }
- /// <summary>
- /// 执行字符串并返回双精度值
- /// </summary>
- /// <param name="name">执行字符串名称</param>
- /// <returns>执行结果</returns>
- publicdouble EvaluateDouble(string name)
- {
- return (double)Evaluate(name);
- }
- /// <summary>
- /// 执行字符串并返回长整型数值
- /// </summary>
- /// <param name="name">执行字符串名称</param>
- /// <returns>执行结果</returns>
- publiclong EvaluateLong(string name)
- {
- return (long)Evaluate(name);
- }
- /// <summary>
- /// 执行字符串并返回十进制数值
- /// </summary>
- /// <param name="name">执行字符串名称</param>
- /// <returns>执行结果</returns>
- publicdecimal EvaluateDecimal(string name)
- {
- return (decimal)Evaluate(name);
- }
- /// <summary>
- /// 执行字符串并返回字符串型值
- /// </summary>
- /// <param name="name">执行字符串名称</param>
- /// <returns>执行结果</returns>
- publicstring EvaluateString(string name)
- {
- return (string)Evaluate(name);
- }
- /// <summary>
- /// 执行字符串并返回布尔型值
- /// </summary>
- /// <param name="name">执行字符串名称</param>
- /// <returns>执行结果</returns>
- publicbool EvaluateBool(string name)
- {
- return (bool)Evaluate(name);
- }
- /// <summary>
- /// 执行字符串并返 object 型值
- /// </summary>
- /// <param name="name">执行字符串名称</param>
- /// <returns>执行结果</returns>
- publicobject Evaluate(string name)
- {
- MethodInfo mi = _Compiled.GetType().GetMethod(name);//获取 _Compiled 所属类型中名称为 name 的方法的引用
- return mi.Invoke(_Compiled, null); //执行 mi 所引用的方法
- }
- #endregion
- #region 静态成员
- /// <summary>
- /// 执行表达式并返回整型值
- /// </summary>
- /// <param name="code">要执行的表达式</param>
- /// <returns>运算结果</returns>
- staticpublicint EvaluateToInteger(string code)
- {
- MyEvaluator eval = new MyEvaluator(typeof(int), code, staticMethodName);//生成 Evaluator 类的对像
- return (int)eval.Evaluate(staticMethodName); //执行并返回整型数据
- }
- /// <summary>
- /// 执行表达式并返回双精度值
- /// </summary>
- /// <param name="name">执行字符串名称</param>
- /// <returns>执行结果</returns>
- staticpublicdouble EvaluateToDouble(string code)
- {
- MyEvaluator eval = new MyEvaluator(typeof(double), code, staticMethodName);//生成 Evaluator 类的对像
- return (double)eval.Evaluate(staticMethodName);
- }
- /// <summary>
- /// 执行表达式并返回长整型数值
- /// </summary>
- /// <param name="name">执行字符串名称</param>
- /// <returns>执行结果</returns>
- staticpubliclong EvaluateToLong(string code)
- {
- MyEvaluator eval = new MyEvaluator(typeof(long), code, staticMethodName);//生成 Evaluator 类的对像
- return (long)eval.Evaluate(staticMethodName);
- }
- /// <summary>
- /// 执行表达式并返回十进制数值
- /// </summary>
- /// <param name="name">执行字符串名称</param>
- /// <returns>执行结果</returns>
- staticpublicdecimal EvaluateToDecimal(string code)
- {
- MyEvaluator eval = new MyEvaluator(typeof(decimal), code, staticMethodName);//生成 Evaluator 类的对像
- return (decimal)eval.Evaluate(staticMethodName);
- }
- /// <summary>
- /// 执行表达式并返回字符串型值
- /// </summary>
- /// <param name="code">要执行的表达式</param>
- /// <returns>运算结果</returns>
- staticpublicstring EvaluateToString(string code)
- {
- MyEvaluator eval = new MyEvaluator(typeof(string), code, staticMethodName);//生成 Evaluator 类的对像
- return (string)eval.Evaluate(staticMethodName); //执行并返回字符串型数据
- }
- /// <summary>
- /// 执行表达式并返回布尔型值
- /// </summary>
- /// <param name="code">要执行的表达式</param>
- /// <returns>运算结果</returns>
- staticpublicbool EvaluateToBool(string code)
- {
- MyEvaluator eval = new MyEvaluator(typeof(bool), code, staticMethodName);//生成 Evaluator 类的对像
- return (bool)eval.Evaluate(staticMethodName); //执行并返回布尔型数据
- }
- /// <summary>
- /// 执行表达式并返回 object 型值
- /// </summary>
- /// <param name="code">要执行的表达式</param>
- /// <returns>运算结果</returns>
- staticpublicobject EvaluateToObject(string code)
- {
- MyEvaluator eval = new MyEvaluator(typeof(object), code, staticMethodName);//生成 Evaluator 类的对像
- return eval.Evaluate(staticMethodName); //执行并返回 object 型数据
- }
- #endregion
- #region 私有成员
- /// <summary>
- /// 静态方法的执行字符串名称
- /// </summary>
- privateconststring staticMethodName = "__foo";
- /// <summary>
- /// 用于动态引用生成的类,执行其内部包含的可执行字符串
- /// </summary>
- object _Compiled = null;
- #endregion
- }
- /// <summary>
- /// 可执行字符串项(即一条可执行字符串)
- /// </summary>
- publicclass EvaluatorItem
- {
- /// <summary>
- /// 返回值类型
- /// </summary>
- public Type ReturnType;
- /// <summary>
- /// 执行表达式
- /// </summary>
- publicstring Expression;
- /// <summary>
- /// 执行字符串名称
- /// </summary>
- publicstring Name;
- /// <summary>
- /// 可执行字符串项构造函数
- /// </summary>
- /// <param name="returnType">返回值类型</param>
- /// <param name="expression">执行表达式</param>
- /// <param name="name">执行字符串名称</param>
- public EvaluatorItem(Type returnType, string expression, string name)
- {
- ReturnType = returnType;
- Expression = expression;
- Name = name;
- }
- }
- }
下面是测试类:
- class Test
- {
- /// <summary>
- /// The main entry point for the application.
- /// </summary>
- [STAThread]
- staticvoid Main(string[] args)
- {
- Console.WriteLine("Test0: {0}", MyEvaluator.EvaluateToInteger("(30 + 4) * 2"));
- Console.WriteLine("Test1: {0}", MyEvaluator.EvaluateToString("/"Hello /" + /"There/""));
- Console.WriteLine("Test2: {0}", MyEvaluator.EvaluateToBool("30 == 40"));
- Console.WriteLine("Test3: {0}", MyEvaluator.EvaluateToObject("new DataSet()"));
- Console.WriteLine("Test4: {0}", MyEvaluator.EvaluateToDouble("(12.4+2.2)*0.4"));
- Console.WriteLine("Test5: {0}", MyEvaluator.EvaluateToLong("(12+1000)*1000"));
- Console.WriteLine("Test6: {0}", MyEvaluator.EvaluateToString("/"double max==/"+double.MaxValue"));//decimal.MaxValue+/",/"+
- EvaluatorItem[] items = {
- new EvaluatorItem(typeof(int), "(30 + 4) * 2", "GetNumber"),
- new EvaluatorItem(typeof(string), "/"Hello /" + /"There/"", "GetString"),
- new EvaluatorItem(typeof(bool), "30 == 40", "GetBool"),
- new EvaluatorItem(typeof(object), "new DataSet()", "GetDataSet")
- };
- MyEvaluator eval = new MyEvaluator(items);
- Console.WriteLine("TestStatic0: {0}", eval.EvaluateInt("GetNumber"));
- Console.WriteLine("TestStatic1: {0}", eval.EvaluateString("GetString"));
- Console.WriteLine("TestStatic2: {0}", eval.EvaluateBool("GetBool"));
- Console.WriteLine("TestStatic3: {0}", eval.Evaluate("GetDataSet"));
- Console.ReadLine();
- }
- }
经测试,想要的结果终于出来了。