首页 > 编程语言 >c#动态执行字符串脚本(优化版)

c#动态执行字符串脚本(优化版)

时间:2023-10-07 15:56:03浏览次数:31  
标签:脚本 code string c# listAssemblies 字符串 Evaluator 执行

像javascript中有eval()来执行动态代码,c#中是没有的,于是自己动手丰衣足食,

先来代码

复制代码
  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 using System.Collections.Generic;
  9 
 10 namespace 检漏仪上位机
 11 {
 12     /// <summary>
 13     /// 本类用来将字符串转为可执行文本并执行
 14     /// 从别处复制,勿随意更改!
 15     /// </summary>
 16     public class Evaluator
 17     {
 18         #region 构造函数
 19         /// <summary>
 20         /// 可执行串的构造函数
 21         /// </summary>
 22         /// <param name="items">
 23         /// 可执行字符串数组
 24         /// </param>
 25         public Evaluator(EvaluatorItem[] items, Dictionary<string, string> listAssemblies = null)
 26         {
 27             ConstructEvaluator(items, listAssemblies);      //调用解析字符串构造函数进行解析
 28         }
 29         /// <summary>
 30         /// 可执行串的构造函数
 31         /// </summary>
 32         /// <param name="returnType">返回值类型</param>
 33         /// <param name="expression">执行表达式</param>
 34         /// <param name="name">执行字符串名称</param>
 35         public Evaluator(Type returnType, string expression, string name, Dictionary<string, string> listAssemblies = null)
 36         {
 37             //创建可执行字符串数组
 38             EvaluatorItem[] items = { new EvaluatorItem(returnType, expression, name) };
 39             ConstructEvaluator(items, listAssemblies);      //调用解析字符串构造函数进行解析
 40         }
 41 
 42         public Evaluator(string allCode, string _namespace, string _class, List<string> listAssemblies = null)
 43         {
 44             ConstructEvaluatorByAllCode(allCode, _namespace, _class, listAssemblies);      //调用解析字符串构造函数进行解析
 45         }
 46         /// <summary>
 47         /// 可执行串的构造函数
 48         /// </summary>
 49         /// <param name="item">可执行字符串项</param>
 50         public Evaluator(EvaluatorItem item, Dictionary<string, string> listAssemblies = null)
 51         {
 52             EvaluatorItem[] items = { item };//将可执行字符串项转为可执行字符串项数组
 53             ConstructEvaluator(items, listAssemblies);      //调用解析字符串构造函数进行解析
 54         }
 55         /// <summary>
 56         /// 解析字符串构造函数
 57         /// </summary>
 58         /// <param name="items">待解析字符串数组</param>
 59         private void ConstructEvaluator(EvaluatorItem[] items, Dictionary<string, string> listAssemblies = null)
 60         {
 61 
 62             //创建C#编译器实例
 63             ICodeCompiler comp = (new CSharpCodeProvider().CreateCompiler());
 64             //编译器的传入参数
 65             CompilerParameters cp = new CompilerParameters();
 66 
 67             cp.ReferencedAssemblies.Add("system.dll");              //添加程序集 system.dll 的引用
 68             cp.ReferencedAssemblies.Add("system.data.dll");         //添加程序集 system.data.dll 的引用
 69             cp.ReferencedAssemblies.Add("system.xml.dll");          //添加程序集 system.xml.dll 的引用
 70             cp.ReferencedAssemblies.Add("System.Windows.Forms.dll");          //添加程序集 system.xml.dll 的引用
 71             cp.GenerateExecutable = false;                          //不生成可执行文件
 72             cp.GenerateInMemory = true;                             //在内存中运行   
 73 
 74             StringBuilder code = new StringBuilder();               //创建代码串
 75             if (listAssemblies != null)
 76             {
 77                 foreach (var item in listAssemblies)
 78                 {
 79                     cp.ReferencedAssemblies.Add(item.Key);              //添加程序集 引用
 80                     code.Append("using "+item.Value + "; \n");
 81 
 82                 }
 83             }
 84             /*
 85              * 添加常见且必须的引用字符串
 86              */
 87             code.Append("using System; \n");
 88             code.Append("using System.Data; \n");
 89             code.Append("using System.Data.SqlClient; \n");
 90             code.Append("using System.Data.OleDb; \n");
 91             code.Append("using System.Xml; \n");
 92             code.Append("using System.Windows.Forms; \n");
 93 
 94             code.Append("namespace EvalGuy { \n");                  //生成代码的命名空间为EvalGuy,和本代码一样   
 95 
 96             code.Append(" public class _Evaluator { \n");          //产生 _Evaluator 类,所有可执行代码均在此类中运行
 97             foreach (EvaluatorItem item in items)               //遍历每一个可执行字符串项
 98             {
 99                 code.AppendFormat("    public {0} {1}() ",          //添加定义公共函数代码
100                                 item.ReturnType == null ? "void" : item.ReturnType.Name,             //函数返回值为可执行字符串项中定义的返回值类型
101                                   item.Name);                       //函数名称为可执行字符串项中定义的执行字符串名称
102                 code.Append("{ ");                                  //添加函数开始括号
103                 if (item.ReturnType != null)
104                     code.AppendFormat("return ({0});", item.Expression);//添加函数体,返回可执行字符串项中定义的表达式的值
105                 else
106                 {
107                     code.Append(item.Expression);//添加函数体,返回可执行字符串项中定义的表达式的值
108                 }
109                 code.Append("}\n");                                 //添加函数结束括号
110             }
111             code.Append("} }");                                 //添加类结束和命名空间结束括号   
112 
113             //得到编译器实例的返回结果
114             CompilerResults cr = comp.CompileAssemblyFromSource(cp, code.ToString());
115 
116             if (cr.Errors.HasErrors)                            //如果有错误
117             {
118                 StringBuilder error = new StringBuilder();          //创建错误信息字符串
119                 error.Append("编译有错误的表达式: ");                //添加错误文本
120                 foreach (CompilerError err in cr.Errors)            //遍历每一个出现的编译错误
121                 {
122                     error.AppendFormat("{0}\n", err.ErrorText);     //添加进错误文本,每个错误后换行
123                 }
124                 throw new Exception("编译错误: " + error.ToString());//抛出异常
125             }
126             Assembly a = cr.CompiledAssembly;                       //获取编译器实例的程序集
127             _Compiled = a.CreateInstance("EvalGuy._Evaluator");     //通过程序集查找并声明 EvalGuy._Evaluator 的实例
128         }
129 
130         private void ConstructEvaluatorByAllCode(string allcode, string _namespace, string _class, List<string> listAssemblies)
131         {
132             if (listAssemblies == null)
133             {
134                 listAssemblies = new List<string>();
135             }
136             //创建C#编译器实例
137             ICodeCompiler comp = (new CSharpCodeProvider().CreateCompiler());
138             //编译器的传入参数
139             CompilerParameters cp = new CompilerParameters();
140             if (!listAssemblies.Contains("system.dll"))
141             {
142                 listAssemblies.Add("system.dll");
143                 listAssemblies.Add("system.data.dll");
144                 listAssemblies.Add("system.xml.dll");
145             }
146             foreach (var item in listAssemblies)
147             {
148                 cp.ReferencedAssemblies.Add(item);
149             }
150 
151             cp.GenerateExecutable = false;                          //不生成可执行文件
152             cp.GenerateInMemory = true;                             //在内存中运行   
153 
154 
155             //得到编译器实例的返回结果
156             CompilerResults cr = comp.CompileAssemblyFromSource(cp, allcode);
157 
158             if (cr.Errors.HasErrors)                            //如果有错误
159             {
160                 StringBuilder error = new StringBuilder();          //创建错误信息字符串
161                 error.Append("编译有错误的表达式: ");                //添加错误文本
162                 foreach (CompilerError err in cr.Errors)            //遍历每一个出现的编译错误
163                 {
164                     error.AppendFormat("{0}\n", err.ErrorText);     //添加进错误文本,每个错误后换行
165                 }
166                 throw new Exception("编译错误: " + error.ToString());//抛出异常
167             }
168             Assembly a = cr.CompiledAssembly;                       //获取编译器实例的程序集
169             _Compiled = a.CreateInstance($"{_namespace}.{_class}");     //通过程序集查找并声明 EvalGuy._Evaluator 的实例
170         }
171         #endregion
172 
173         #region 公有成员
174         /// <summary>
175         /// 执行字符串并返回整型值
176         /// </summary>
177         /// <param name="name">执行字符串名称</param>
178         /// <returns>执行结果</returns>
179         public int EvaluateInt(string name)
180         {
181             return (int)Evaluate(name);
182         }
183         /// <summary>
184         /// 执行字符串并返回字符串型值
185         /// </summary>
186         /// <param name="name">执行字符串名称</param>
187         /// <returns>执行结果</returns>
188         public string EvaluateString(string name)
189         {
190             return (string)Evaluate(name);
191         }
192         /// <summary>
193         /// 执行字符串并返回布尔型值
194         /// </summary>
195         /// <param name="name">执行字符串名称</param>
196         /// <returns>执行结果</returns>
197         public bool EvaluateBool(string name)
198         {
199             return (bool)Evaluate(name);
200         }
201         /// <summary>
202         /// 执行字符串并返 object 型值
203         /// </summary>
204         /// <param name="name">执行字符串名称</param>
205         /// <returns>执行结果</returns>
206         public object Evaluate(string name)
207         {
208             MethodInfo mi = _Compiled.GetType().GetMethod(name);//获取 _Compiled 所属类型中名称为 name 的方法的引用
209             return mi.Invoke(_Compiled, null);                  //执行 mi 所引用的方法
210         }
211         #endregion
212 
213         #region 静态成员
214         /// <summary>
215         /// 执行表达式并返回整型值
216         /// </summary>
217         /// <param name="code">要执行的表达式</param>
218         /// <param name="listAssemblies">需要引用到类库,key:dll名称,value:命名空间名称</param>
219         /// <returns>运算结果</returns>
220         static public int EvaluateToInteger(string code, Dictionary<string, string> listAssemblies = null)
221         {
222             Evaluator eval = new Evaluator(typeof(int), code, staticMethodName, listAssemblies);//生成 Evaluator 类的对像
223             return (int)eval.Evaluate(staticMethodName);                        //执行并返回整型数据
224         }
225         /// <summary>
226         /// 执行表达式并返回字符串型值
227         /// </summary>
228         /// <param name="code">要执行的表达式</param>
229         /// <param name="listAssemblies">需要引用到类库,key:dll名称,value:命名空间名称</param>
230         /// <returns>运算结果</returns>
231         static public string EvaluateToString(string code, Dictionary<string, string> listAssemblies = null)
232         {
233             Evaluator eval = new Evaluator(typeof(string), code, staticMethodName, listAssemblies);//生成 Evaluator 类的对像
234             return (string)eval.Evaluate(staticMethodName);                     //执行并返回字符串型数据
235         }
236         /// <summary>
237         /// 执行表达式并返回布尔型值
238         /// </summary>
239         /// <param name="code">要执行的表达式</param>
240         /// <param name="listAssemblies">需要引用到类库,key:dll名称,value:命名空间名称</param>
241         /// <returns>运算结果</returns>
242         static public bool EvaluateToBool(string code, Dictionary<string, string> listAssemblies = null)
243         {
244             Evaluator eval = new Evaluator(typeof(bool), code, staticMethodName, listAssemblies);//生成 Evaluator 类的对像
245             return (bool)eval.Evaluate(staticMethodName);                       //执行并返回布尔型数据
246         }
247         /// <summary>
248         /// 执行表达式并返回 object 型值
249         /// </summary>
250         /// <param name="code">要执行的表达式</param>
251         /// <param name="listAssemblies">需要引用到类库,key:dll名称,value:命名空间名称</param>
252         /// <returns>运算结果</returns>
253         static public object EvaluateToObject(string code, Dictionary<string, string> listAssemblies = null)
254         {
255             Evaluator eval = new Evaluator(typeof(object), code, staticMethodName, listAssemblies);//生成 Evaluator 类的对像
256             return eval.Evaluate(staticMethodName);                             //执行并返回 object 型数据
257         }
258         /// <summary>
259         /// 执行一个无返回式的代码
260         /// </summary>
261         /// <param name="code"></param>
262         /// <param name="listAssemblies">需要引用到类库,key:dll名称,value:命名空间名称</param>
263         static public void EvaluateToVoid(string code, Dictionary<string, string> listAssemblies = null)
264         {
265             Evaluator eval = new Evaluator(null, code, staticMethodName, listAssemblies);//生成 Evaluator 类的对像
266             eval.Evaluate(staticMethodName);                             //执行并返回 object 型数据
267         }
268         /// <summary>
269         /// 执行一个全代码
270         /// </summary>
271         /// <param name="code">全代码,包含命名空间引用,命名空间声明,类声明,函数声明等</param>
272         /// <param name="_namespace"></param>
273         /// <param name="_class"></param>
274         /// <param name="methodName">函数</param>
275         /// <param name="listAssemblies">需要引用到类库</param>
276         public static void EvaluateByAllCode(string code, string _namespace, string _class, string methodName, List<string> listAssemblies = null)
277         {
278             Evaluator eval = new Evaluator(code, _namespace, _class, listAssemblies);//生成 Evaluator 类的对像
279             eval.Evaluate(methodName);
280         }
281         #endregion
282 
283         #region 私有成员
284         /// <summary>
285         /// 静态方法的执行字符串名称
286         /// </summary>
287         private const string staticMethodName = "__foo";
288         /// <summary>
289         /// 用于动态引用生成的类,执行其内部包含的可执行字符串
290         /// </summary>
291         object _Compiled = null;
292         #endregion
293     }
294     /// <summary>
295     /// 可执行字符串项(即一条可执行字符串)
296     /// </summary>
297     public class EvaluatorItem
298     {
299         /// <summary>
300         /// 返回值类型
301         /// </summary>
302         public Type ReturnType;
303         /// <summary>
304         /// 执行表达式
305         /// </summary>
306         public string Expression;
307         /// <summary>
308         /// 执行字符串名称
309         /// </summary>
310         public string Name;
311         /// <summary>
312         /// 可执行字符串项构造函数
313         /// </summary>
314         /// <param name="returnType">返回值类型</param>
315         /// <param name="expression">执行表达式</param>
316         /// <param name="name">执行字符串名称</param>
317         public EvaluatorItem(Type returnType, string expression, string name)
318         {
319             ReturnType = returnType;
320             Expression = expression;
321             Name = name;
322         }
323     }
324 }
复制代码

调用一个无返回值的代码,显示一个提示框

Evaluator.EvaluateToVoid("MessageBox.Show(\"Test\");",new Dictionary<string, string>() { { "System.Windows.Forms.dll", "System.Windows.Forms" } });

调用一个计算返回整型

            Evaluator.EvaluateToInteger("1+2*3");

调用一个全代码

复制代码
            string str = @"using System;
namespace a
{ 
    public class b
    {
        public  void c()
        {
            Console.WriteLine(1);
        }
    }
}";

Evaluator.EvaluateByAllCode(str, "a", "b", "c");
复制代码

功能就这么多

 

标签:脚本,code,string,c#,listAssemblies,字符串,Evaluator,执行
From: https://www.cnblogs.com/chinasoft/p/17746518.html

相关文章

  • idea报错:Failed to execute goal org.codehaus.mojo:exec-maven-plugin:3.0.0:exec (d
    idea版本:​​2020.3​​idea报错:在查阅了资料以后发现是​​IDEA2020​​的兼容问题 Failedtoexecutegoalorg.codehaus.mojo:exec-maven-plugin:3.0.0:exec(default-cli)onprojectsms:Commandexecutionfailed.解决方法:1、测试不要用​​main​​方法测试,使用​​......
  • centos7磁盘挂载与LVM扩容
    目录磁盘挂载查看一下现有磁盘创建磁盘分区创建PV(物理卷)创建VG(卷组)创建LV(逻辑卷)格式化分区挂载分区挂载分配文件/etc/fstab扩容逻辑分区创建磁盘分区重读分区表格式化分区扩容VG扩容LV刷新文件系统df-h查看新申请的ECS,磁盘一般不给挂好,非得为难我这菜鸟自己操作磁盘挂......
  • 简述memcached的工作原理
     Memcached只支持能序列化的数据类型,不支持持久化,基于Key-Value的内存缓存系统1.内存分配机制 应用程序运行需要使用内存存储数据,但对于一个缓存系统来说,申请内存、释放内存将十分频繁,非常容易导致大量内存碎片,最后导致无连续可用内存可用。 Memcached采用了Slab......
  • nginx实现后端tomcat的负载均衡调度
    1.负载均衡主机和网络地址规划10.0.0.152proxy.magedu.orgnginx10.0.0.150t1.magedu.orgtomcat110.0.0.160t2.magedu.orgtomcat2#只需在10.0.0.52的nginx主机上实现域名解析[root@localhost~]#cat/etc/hosts127.0.0.1localhost......
  • TypeError: Cannot read properties of undefined (reading '0')
    今天取请求返回值时报的一个错误,要取返回值中数组下标为零的数据,错误显示说未定义。检查之后发现要取的数据是请求返回的data中data,少嵌套了一层data导致数据为空报错。(返回数据的路径可以右键Copypropertypath,这样就不会错了)......
  • 总结tomcat优化方法
     ##1、概述Tomcat的运行依赖于JVM,从虚拟机的角度把Tomcat的调整分为外部环境调优和Tomcat自身调优两部分##2、外部环境JVM调优Tomcat首先跑在JVM之上的,因为它的启动其实也只是一个java命令行,首先我们需要对这个JAVA的启动命令行进行调优。帮助:manjava......
  • Go - Creating One - Time Structs
     person:=struct{IdintNamestringEmailstring}{1,"ChangSauSheong","[email protected]"} person=struct{IdintNamestringEmails......
  • npm run dev 提示 { parser: "babylon" } is deprecated; we now treat it as { parse
    修改emacsnode_modules/vue-loader/lib/template-compiler/index.js将以下代码中的babylon替换babelif(!isProduction){code=prettier.format(code,{semi:false,parser:'babylon'})}if(!isProduction){code=prettier.format(code,{semi:false......
  • Oracle常用语句
    一、表注释1、添加表注释commentontablescheduler_tableis'调度表'2、删除表注释commentontablescheduler_tableis''3、查询表注释select*fromuser_tab_commentswheretable_name='SCHEDULER_TABLE'4、添加字段注释commentoncolumnscheduler_table.idis&#......
  • 基于redis5的redis cluster部署
     1.创建rediscluster集群的环境准备1.1.#每个redis节点采用相同的相同的redis版本、相同的密码、硬件配置;所有redis服务器必须没有任何数据;准备六台主机,地址如下:10.0.0.15010.0.0.16010.0.0.17010.0.0.18010.0.0.19010.0.0.2002.启用redis......