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

2023-03-30 20:19:24 浏览数 (2)

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

先来代码

代码语言:javascript复制
  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 }

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

代码语言:javascript复制
Evaluator.EvaluateToVoid("MessageBox.Show("Test");",new Dictionary<string, string>() { { "System.Windows.Forms.dll", "System.Windows.Forms" } });

调用一个计算返回整型

代码语言:javascript复制
 Evaluator.EvaluateToInteger("1 2*3");

调用一个全代码

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

Evaluator.EvaluateByAllCode(str, "a", "b", "c");

功能就这么多

0 人点赞