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

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

先来代码

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

  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     /// 
 13     /// 本类用来将字符串转为可执行文本并执行
 14     /// 从别处复制,勿随意更改!
 15     /// 
 16     public class Evaluator
 17     {
 18         #region 构造函数
 19         /// 
 20         /// 可执行串的构造函数
 21         /// 
 22         /// 
 23         /// 可执行字符串数组
 24         /// 
 25         public Evaluator(EvaluatorItem[] items, Dictionarystring, string> listAssemblies = null)
 26         {
 27             ConstructEvaluator(items, listAssemblies);      //调用解析字符串构造函数进行解析
 28         }
 29         /// 
 30         /// 可执行串的构造函数
 31         /// 
 32         /// 返回值类型
 33         /// 执行表达式
 34         /// 执行字符串名称
 35         public Evaluator(Type returnType, string expression, string name, Dictionarystring, 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, Liststring> listAssemblies = null)
 43         {
 44             ConstructEvaluatorByAllCode(allCode, _namespace, _class, listAssemblies);      //调用解析字符串构造函数进行解析
 45         }
 46         /// 
 47         /// 可执行串的构造函数
 48         /// 
 49         /// 可执行字符串项
 50         public Evaluator(EvaluatorItem item, Dictionarystring, string> listAssemblies = null)
 51         {
 52             EvaluatorItem[] items = { item };//将可执行字符串项转为可执行字符串项数组
 53             ConstructEvaluator(items, listAssemblies);      //调用解析字符串构造函数进行解析
 54         }
 55         /// 
 56         /// 解析字符串构造函数
 57         /// 
 58         /// 待解析字符串数组
 59         private void ConstructEvaluator(EvaluatorItem[] items, Dictionarystring, 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, Liststring> listAssemblies)
131         {
132             if (listAssemblies == null)
133             {
134                 listAssemblies = new Liststring>();
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         /// 
175         /// 执行字符串并返回整型值
176         /// 
177         /// 执行字符串名称
178         /// 执行结果
179         public int EvaluateInt(string name)
180         {
181             return (int)Evaluate(name);
182         }
183         /// 
184         /// 执行字符串并返回字符串型值
185         /// 
186         /// 执行字符串名称
187         /// 执行结果
188         public string EvaluateString(string name)
189         {
190             return (string)Evaluate(name);
191         }
192         /// 
193         /// 执行字符串并返回布尔型值
194         /// 
195         /// 执行字符串名称
196         /// 执行结果
197         public bool EvaluateBool(string name)
198         {
199             return (bool)Evaluate(name);
200         }
201         /// 
202         /// 执行字符串并返 object 型值
203         /// 
204         /// 执行字符串名称
205         /// 执行结果
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         /// 
215         /// 执行表达式并返回整型值
216         /// 
217         /// 要执行的表达式
218         /// 需要引用到类库,key:dll名称,value:命名空间名称
219         /// 运算结果
220         static public int EvaluateToInteger(string code, Dictionarystring, string> listAssemblies = null)
221         {
222             Evaluator eval = new Evaluator(typeof(int), code, staticMethodName, listAssemblies);//生成 Evaluator 类的对像
223             return (int)eval.Evaluate(staticMethodName);                        //执行并返回整型数据
224         }
225         /// 
226         /// 执行表达式并返回字符串型值
227         /// 
228         /// 要执行的表达式
229         /// 需要引用到类库,key:dll名称,value:命名空间名称
230         /// 运算结果
231         static public string EvaluateToString(string code, Dictionarystring, string> listAssemblies = null)
232         {
233             Evaluator eval = new Evaluator(typeof(string), code, staticMethodName, listAssemblies);//生成 Evaluator 类的对像
234             return (string)eval.Evaluate(staticMethodName);                     //执行并返回字符串型数据
235         }
236         /// 
237         /// 执行表达式并返回布尔型值
238         /// 
239         /// 要执行的表达式
240         /// 需要引用到类库,key:dll名称,value:命名空间名称
241         /// 运算结果
242         static public bool EvaluateToBool(string code, Dictionarystring, string> listAssemblies = null)
243         {
244             Evaluator eval = new Evaluator(typeof(bool), code, staticMethodName, listAssemblies);//生成 Evaluator 类的对像
245             return (bool)eval.Evaluate(staticMethodName);                       //执行并返回布尔型数据
246         }
247         /// 
248         /// 执行表达式并返回 object 型值
249         /// 
250         /// 要执行的表达式
251         /// 需要引用到类库,key:dll名称,value:命名空间名称
252         /// 运算结果
253         static public object EvaluateToObject(string code, Dictionarystring, string> listAssemblies = null)
254         {
255             Evaluator eval = new Evaluator(typeof(object), code, staticMethodName, listAssemblies);//生成 Evaluator 类的对像
256             return eval.Evaluate(staticMethodName);                             //执行并返回 object 型数据
257         }
258         /// 
259         /// 执行一个无返回式的代码
260         /// 
261         /// 
262         /// 需要引用到类库,key:dll名称,value:命名空间名称
263         static public void EvaluateToVoid(string code, Dictionarystring, string> listAssemblies = null)
264         {
265             Evaluator eval = new Evaluator(null, code, staticMethodName, listAssemblies);//生成 Evaluator 类的对像
266             eval.Evaluate(staticMethodName);                             //执行并返回 object 型数据
267         }
268         /// 
269         /// 执行一个全代码
270         /// 
271         /// 全代码,包含命名空间引用,命名空间声明,类声明,函数声明等
272         /// 
273         /// 
274         /// 函数
275         /// 需要引用到类库
276         public static void EvaluateByAllCode(string code, string _namespace, string _class, string methodName, Liststring> listAssemblies = null)
277         {
278             Evaluator eval = new Evaluator(code, _namespace, _class, listAssemblies);//生成 Evaluator 类的对像
279             eval.Evaluate(methodName);
280         }
281         #endregion
282 
283         #region 私有成员
284         /// 
285         /// 静态方法的执行字符串名称
286         /// 
287         private const string staticMethodName = "__foo";
288         /// 
289         /// 用于动态引用生成的类,执行其内部包含的可执行字符串
290         /// 
291         object _Compiled = null;
292         #endregion
293     }
294     /// 
295     /// 可执行字符串项(即一条可执行字符串)
296     /// 
297     public class EvaluatorItem
298     {
299         /// 
300         /// 返回值类型
301         /// 
302         public Type ReturnType;
303         /// 
304         /// 执行表达式
305         /// 
306         public string Expression;
307         /// 
308         /// 执行字符串名称
309         /// 
310         public string Name;
311         /// 
312         /// 可执行字符串项构造函数
313         /// 
314         /// 返回值类型
315         /// 执行表达式
316         /// 执行字符串名称
317         public EvaluatorItem(Type returnType, string expression, string name)
318         {
319             ReturnType = returnType;
320             Expression = expression;
321             Name = name;
322         }
323     }
324 }

View Code

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

Evaluator.EvaluateToVoid("MessageBox.Show("Test");",new Dictionarystring, 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");

功能就这么多

 

文章来源于互联网:c#动态执行字符串脚本(优化版)

THE END
分享
二维码