在编写C#程序的时候,有时我们需要动态生成一些代码并执行。然而C#不像JavaScript有一个Eval函数,可以动态的执行代码。所有这些功能都要我们自己去完成。如下是实例。

动态创建代码:

  1. using System;
  2. using System.Data;
  3. using System.Configuration;
  4. using System.Text;
  5. using System.CodeDom.Compiler;
  6. using Microsoft.CSharp;
  7. using System.Reflection;
  8.  
  9. namespace EvalGuy
  10. {
  11. /// <summary>
  12. /// 本类用来将字符串转为可执行文本并执行
  13. /// 从别处复制,勿随意更改!
  14. /// </summary>
  15. public class Evaluator
  16. {
  17. #region 构造函数
  18. /// <summary>
  19. /// 可执行串的构造函数
  20. /// </summary>
  21. /// <param name="items">
  22. /// 可执行字符串数组
  23. /// </param>
  24. public Evaluator(EvaluatorItem[] items)
  25. {
  26. ConstructEvaluator(items); //调用解析字符串构造函数进行解析
  27. }
  28. /// <summary>
  29. /// 可执行串的构造函数
  30. /// </summary>
  31. /// <param name="returnType">返回值类型</param>
  32. /// <param name="expression">执行表达式</param>
  33. /// <param name="name">执行字符串名称</param>
  34. public Evaluator(Type returnType, string expression, string name)
  35. {
  36. //创建可执行字符串数组
  37. EvaluatorItem[] items = { new EvaluatorItem(returnType, expression, name) };
  38. ConstructEvaluator(items); //调用解析字符串构造函数进行解析
  39. }
  40. /// <summary>
  41. /// 可执行串的构造函数
  42. /// </summary>
  43. /// <param name="item">可执行字符串项</param>
  44. public Evaluator(EvaluatorItem item)
  45. {
  46. EvaluatorItem[] items = { item };//将可执行字符串项转为可执行字符串项数组
  47. ConstructEvaluator(items); //调用解析字符串构造函数进行解析
  48. }
  49. /// <summary>
  50. /// 解析字符串构造函数
  51. /// </summary>
  52. /// <param name="items">待解析字符串数组</param>
  53. private void ConstructEvaluator(EvaluatorItem[] items)
  54. {
  55. //创建C#编译器实例
  56. ICodeCompiler comp = (new CSharpCodeProvider().CreateCompiler());
  57. //编译器的传入参数
  58. CompilerParameters cp = new CompilerParameters();
  59.  
  60. cp.ReferencedAssemblies.Add("system.dll"); //添加程序集 system.dll 的引用
  61. cp.ReferencedAssemblies.Add("system.data.dll"); //添加程序集 system.data.dll 的引用
  62. cp.ReferencedAssemblies.Add("system.xml.dll"); //添加程序集 system.xml.dll 的引用
  63. cp.GenerateExecutable = false; //不生成可执行文件
  64. cp.GenerateInMemory = true; //在内存中运行
  65.  
  66. StringBuilder code = new StringBuilder(); //创建代码串
  67. /*
  68. * 添加常见且必须的引用字符串
  69. */
  70. code.Append("using System; \n");
  71. code.Append("using System.Data; \n");
  72. code.Append("using System.Data.SqlClient; \n");
  73. code.Append("using System.Data.OleDb; \n");
  74. code.Append("using System.Xml; \n");
  75.  
  76. code.Append("namespace EvalGuy { \n"); //生成代码的命名空间为EvalGuy,和本代码一样
  77.  
  78. code.Append(" public class _Evaluator { \n"); //产生 _Evaluator 类,所有可执行代码均在此类中运行
  79. foreach (EvaluatorItem item in items) //遍历每一个可执行字符串项
  80. {
  81. code.AppendFormat(" public {0} {1}() ", //添加定义公共函数代码
  82. item.ReturnType.Name, //函数返回值为可执行字符串项中定义的返回值类型
  83. item.Name); //函数名称为可执行字符串项中定义的执行字符串名称
  84. code.Append("{ "); //添加函数开始括号
  85. code.AppendFormat("return ({0});", item.Expression);//添加函数体,返回可执行字符串项中定义的表达式的值
  86. code.Append("}\n"); //添加函数结束括号
  87. }
  88. code.Append("} }"); //添加类结束和命名空间结束括号
  89.  
  90. //得到编译器实例的返回结果
  91. CompilerResults cr = comp.CompileAssemblyFromSource(cp, code.ToString());
  92.  
  93. if (cr.Errors.HasErrors) //如果有错误
  94. {
  95. StringBuilder error = new StringBuilder(); //创建错误信息字符串
  96. error.Append("编译有错误的表达式: "); //添加错误文本
  97. foreach (CompilerError err in cr.Errors) //遍历每一个出现的编译错误
  98. {
  99. error.AppendFormat("{0}\n", err.ErrorText); //添加进错误文本,每个错误后换行
  100. }
  101. throw new Exception("编译错误: " + error.ToString());//抛出异常
  102. }
  103. Assembly a = cr.CompiledAssembly; //获取编译器实例的程序集
  104. _Compiled = a.CreateInstance("EvalGuy._Evaluator"); //通过程序集查找并声明 EvalGuy._Evaluator 的实例
  105. }
  106. #endregion
  107.  
  108. #region 公有成员
  109. /// <summary>
  110. /// 执行字符串并返回整型值
  111. /// </summary>
  112. /// <param name="name">执行字符串名称</param>
  113. /// <returns>执行结果</returns>
  114. public int EvaluateInt(string name)
  115. {
  116. return (int)Evaluate(name);
  117. }
  118. /// <summary>
  119. /// 执行字符串并返回字符串型值
  120. /// </summary>
  121. /// <param name="name">执行字符串名称</param>
  122. /// <returns>执行结果</returns>
  123. public string EvaluateString(string name)
  124. {
  125. return (string)Evaluate(name);
  126. }
  127. /// <summary>
  128. /// 执行字符串并返回布尔型值
  129. /// </summary>
  130. /// <param name="name">执行字符串名称</param>
  131. /// <returns>执行结果</returns>
  132. public bool EvaluateBool(string name)
  133. {
  134. return (bool)Evaluate(name);
  135. }
  136. /// <summary>
  137. /// 执行字符串并返 object 型值
  138. /// </summary>
  139. /// <param name="name">执行字符串名称</param>
  140. /// <returns>执行结果</returns>
  141. public object Evaluate(string name)
  142. {
  143. MethodInfo mi = _Compiled.GetType().GetMethod(name);//获取 _Compiled 所属类型中名称为 name 的方法的引用
  144. return mi.Invoke(_Compiled, null); //执行 mi 所引用的方法
  145. }
  146. #endregion
  147.  
  148. #region 静态成员
  149. /// <summary>
  150. /// 执行表达式并返回整型值
  151. /// </summary>
  152. /// <param name="code">要执行的表达式</param>
  153. /// <returns>运算结果</returns>
  154. static public int EvaluateToInteger(string code)
  155. {
  156. Evaluator eval = new Evaluator(typeof(int), code, staticMethodName);//生成 Evaluator 类的对像
  157. return (int)eval.Evaluate(staticMethodName); //执行并返回整型数据
  158. }
  159. /// <summary>
  160. /// 执行表达式并返回字符串型值
  161. /// </summary>
  162. /// <param name="code">要执行的表达式</param>
  163. /// <returns>运算结果</returns>
  164. static public string EvaluateToString(string code)
  165. {
  166. Evaluator eval = new Evaluator(typeof(string), code, staticMethodName);//生成 Evaluator 类的对像
  167. return (string)eval.Evaluate(staticMethodName); //执行并返回字符串型数据
  168. }
  169. /// <summary>
  170. /// 执行表达式并返回布尔型值
  171. /// </summary>
  172. /// <param name="code">要执行的表达式</param>
  173. /// <returns>运算结果</returns>
  174. static public bool EvaluateToBool(string code)
  175. {
  176. Evaluator eval = new Evaluator(typeof(bool), code, staticMethodName);//生成 Evaluator 类的对像
  177. return (bool)eval.Evaluate(staticMethodName); //执行并返回布尔型数据
  178. }
  179. /// <summary>
  180. /// 执行表达式并返回 object 型值
  181. /// </summary>
  182. /// <param name="code">要执行的表达式</param>
  183. /// <returns>运算结果</returns>
  184. static public object EvaluateToObject(string code)
  185. {
  186. Evaluator eval = new Evaluator(typeof(object), code, staticMethodName);//生成 Evaluator 类的对像
  187. return eval.Evaluate(staticMethodName); //执行并返回 object 型数据
  188. }
  189. #endregion
  190.  
  191. #region 私有成员
  192. /// <summary>
  193. /// 静态方法的执行字符串名称
  194. /// </summary>
  195. private const string staticMethodName = "__foo";
  196. /// <summary>
  197. /// 用于动态引用生成的类,执行其内部包含的可执行字符串
  198. /// </summary>
  199. object _Compiled = null;
  200. #endregion
  201. }
  202. /// <summary>
  203. /// 可执行字符串项(即一条可执行字符串)
  204. /// </summary>
  205. public class EvaluatorItem
  206. {
  207. /// <summary>
  208. /// 返回值类型
  209. /// </summary>
  210. public Type ReturnType;
  211. /// <summary>
  212. /// 执行表达式
  213. /// </summary>
  214. public string Expression;
  215. /// <summary>
  216. /// 执行字符串名称
  217. /// </summary>
  218. public string Name;
  219. /// <summary>
  220. /// 可执行字符串项构造函数
  221. /// </summary>
  222. /// <param name="returnType">返回值类型</param>
  223. /// <param name="expression">执行表达式</param>
  224. /// <param name="name">执行字符串名称</param>
  225. public EvaluatorItem(Type returnType, string expression, string name)
  226. {
  227. ReturnType = returnType;
  228. Expression = expression;
  229. Name = name;
  230. }
  231. }
  232. }

调用方法:注意引用EvalGuy命名空间:

  1. Console.WriteLine("Test0: {0}", Evaluator.EvaluateToInteger("(30 + 4) * 2"));
  2. Console.WriteLine("Test1: {0}", Evaluator.EvaluateToString("\"Hello \" + \"There\""));
  3. Console.WriteLine("Test2: {0}", Evaluator.EvaluateToBool("30 == 40"));
  4. Console.WriteLine("Test3: {0}", Evaluator.EvaluateToObject("new DataSet()"));
  5.  
  6. EvaluatorItem[] items = {
  7. new EvaluatorItem(typeof(int), "(30 + 4) * 2", "GetNumber"),
  8. new EvaluatorItem(typeof(string), "\"Hello \" + \"There\"",
  9. "GetString"),
  10. new EvaluatorItem(typeof(bool), "30 == 40", "GetBool"),
  11. new EvaluatorItem(typeof(object), "new DataSet()", "GetDataSet")
  12. };
  13.  
  14. Evaluator eval = new Evaluator(items);
  15. Console.WriteLine("TestStatic0: {0}", eval.EvaluateInt("GetNumber"));
  16. Console.WriteLine("TestStatic1: {0}", eval.EvaluateString("GetString"));
  17. Console.WriteLine("TestStatic2: {0}", eval.EvaluateBool("GetBool"));
  18. Console.WriteLine("TestStatic3: {0}", eval.Evaluate("GetDataSet"));

转自:http://hi.baidu.com/yxw740/item/e4d256f2208590d342c36acc

C#动态执行字符串(动态创建代码)的更多相关文章

  1. 如何执行字符串的PHP代码

    如何执行字符串的PHP代码 最近因项目需要,引出一个议题:如何执行字符串的php代码(php和html混写). 注:传统情况下,php代码存储在文件中,直接运行文件即可.以下讨论的情况是,如果php代 ...

  2. 第6.3节 Python动态执行之动态编译的compile函数

    Python支持动态代码主要三个函数,分别是compile.eval和exec.本节介绍compile函数的语法和相关使用.compile函数用来编译一段字符串的源码,将其编译为字节码或者AST(抽像 ...

  3. 执行字符串或注释代码段的方法(eval、exec、execfile)

    eval:计算字符串中的表达式exec:执行字符串中的语句execfile:用来执行一个文件 需注意的是,exec是一个语句,而eval()和execfile()则是内建built-in函数. 1 2 ...

  4. (转+整理)C#中动态执行代码

    通过微软提供的CSharpCodeProvider,CompilerParameters,CompilerResults等类,可以在运行时,动态执行自己写的代码文件.原理就是把你的代码文件动态编译成e ...

  5. 动态执行C#代码

    using System; using System.CodeDom.Compiler;using System.Collections.Generic;using System.Linq;using ...

  6. 执行C#动态代码

    执行C#动态代码 using System; using System.Data; using System.Configuration; using System.Text; using Syste ...

  7. Spring Boot 创建定时任务(配合数据库动态执行)

    序言:创建定时任务非常简单,主要有两种创建方式:一.基于注解(@Scheduled) 二.基于接口(SchedulingConfigurer). 前者相信大家都很熟悉,但是实际使用中我们往往想从数据库 ...

  8. mysql 字符串分割 和 动态执行拼接sql

    本人以前主要用的是MSSQL,最近项目在使用MYSQL,自己是一个 典型的小白.今天就记录一下 一个mysql存储过程,里面需要分割字符串和 动态执行sql语句. 关于字符串 分割我开始使用 LOCA ...

  9. 动态执行文本vba代码

    动态执行文本vba代码 Public Sub StringExecute(s As String) Dim vbComp As Object Set vbComp = ThisWorkbook.VBP ...

随机推荐

  1. 观察者模式及Java实现例子

    http://www.cnblogs.com/mengdd/archive/2013/02/07/2908929.html 观察者模式 观察者模式 Observer 观察者模式定义了一种一对多的依赖关 ...

  2. visual.studio.15.preview5 编译器

    前段时间微软更新了新版开发工具visual studio 15 preview5,安装后连文件结构目录都变了,想提取编译器还找不到. 不是原来的VC\BIN目录,已迁移到IDE\MSVC\14.10. ...

  3. [工具开发] keepalived使用nagios监控脚本

    最近在做开发和办公环境的高可用,采用的是keepalived:keepalived基于Linux内核支持的LVS,既能实现高可用,又能实现负载均衡,非常实用. keepalived监控服务状态时可以用 ...

  4. SQL Server 2008 数据库通过镜像同步备份(数据库热备)

    数据库镜像运行模式: 异步数据库镜像模式(异步,高性能模式) 同步数据库镜像模式(同步,高安全模式) 参考资料: http://technet.microsoft.com/zh-cn/library/ ...

  5. Notice: Trying to get property of non-object problem(PHP)解决办法 中间件只能跳转不能返任何数据

    这里实际是调用了一个zend的数据库访问的方法,使用了fetchAll方法,但由于数据库中没有该记录,所以返回的对象是null,所以我就判断对象是否为null: 复制代码代码如下: if($obj== ...

  6. Java为什么会引入及如何使用Unsafe

    综述 sun.misc.Unsafe至少从2004年Java1.4开始就存在于Java中了.在Java9中,为了提高JVM的可维护性,Unsafe和许多其他的东西一起都被作为内部使用类隐藏起来了.但是 ...

  7. [CF #288-C] Anya and Ghosts (贪心)

    题目链接:http://codeforces.com/contest/508/problem/C 题目大意:给你三个数,m,t,r,代表晚上有m个幽灵,我有无限支蜡烛,每支蜡烛能够亮t秒,房间需要r支 ...

  8. Website Speed Optimization Guide for Google PageSpeed Rules

    原链接地址:http://www.artzstudio.com/2016/07/website-speed-optimization-guide-for-google-pagespeed-rules/ ...

  9. AngularJs 简单实现全选,多选操作

    很多时候我们在处理CURD(增删改查)的时候需要实现批量操作数据,这时候就必须使用多选操作. Angular 中实现如下(当然还有很多种比笔者写的更好的方法,这里只是简单的实现.) demo 演示地址 ...

  10. ZeroClipboard实现复制

    今天利用ZeroClipboard实现了批量复制ip到剪贴版的公里,第一种方式总是有错,需要点击两次才能成功复制,第二种方法成功.在这里记录下,方法一: $('#copy_ips').zclip({ ...