c#動態執行字符串腳本(優化版)

像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 }
View Code

調用一個無返回值的代碼,顯示一個提示框

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");

功能就這麼多

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章