C#动态编译与执行代码
最近在项目中遇到一个这样的需求,要求规则动态变化,并且用户可以自定义,经查多种资料 ,可以用动态运行类来实现。
在此之前,我们先来了解几个类型,方法及属性,CSharpCodeProvider、ICodeCompiler、CompilerParameters、CompilerResults、Assembly。。
1、类 CSharpCodeProvider
提供对C#代码生成器和代码编译器的实例的访问。在实例之前要要引用 Microsoft.CSharp及System.CodeDom.Compiler 命名空间。
//
// 摘要:
// Provides access to instances of the C# code generator and code compiler.
CSharpCodeProvider codeProvider = new CSharpCodeProvider();
3、类 CompilerParameters
表示用于调用编译器的参数。
//
// 摘要:
// Represents the parameters used to invoke a compiler.
CompilerParameters compParameters = new CompilerParameters();
方法 ReferencedAssemblies:获取当前项目所引用的程序集。Add方法为程序集添加引用。
compParameters.ReferencedAssemblies.Add(@"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5\System.Core.dll");
compParameters.ReferencedAssemblies.Add(@"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5\System.XML.dll");
compParameters.ReferencedAssemblies.Add(@"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5\System.Xml.Linq.dll");
GenerateExecutable:获取或设置一个值,该值指示是否生成可执行文件。若此属性为false,则生成DLL,默认是false。
GenerateInMemory:获取或设置一个值,该值指示是否在内存中生成输出
3、接口 ICodeCompiler
定义用于调用源代码编译的接口或使用指定编译器的CodeDOM树。每种编译方法都接受指示编译器的CompilerParameters对象,并返回指示编译结果的CompilerResults对象。
CompilerResults res= codeProvider.CompilerAssemblyFromSource(CompilerParameters option, string source):使用指定的编译器,从包含源代码的字符串设置编译程序集。
4、CompilerResults
表示从编译器返回的编译结果。
CompiledAssembly:获取或设置以编译的程序集,Assembly类型。
5、Assembly 程序集
assemby =res.CompiledAssembly
根据程序集创建类实例
Gets or sets the compiled assembly.
An System.Reflection.Assembly that indicates the compiled assembly.
object myClass= res.CompiledAssembly.CreateInstance("ClassName");
6、Call the method 'MyMethod' with the parameter object array
parametersObj为object[] 类型。
object result = myClass.GetType().GetMethod(methodName).Invoke(myClass, parametersObj);
具体实现代码如下
1 using Microsoft.CSharp; 2 using System; 3 using System.CodeDom.Compiler; 4 using System.Collections.Generic; 5 using System.ComponentModel; 6 using System.Data; 7 using System.Drawing; 8 using System.IO; 9 using System.Linq; 10 using System.Reflection; 11 using System.Text; 12 using System.Text.RegularExpressions; 13 using System.Threading.Tasks; 14 using System.Xml.Serialization; 15 16 namespace DynamicCompileLib 17 { 18 /// <summary> 19 /// 动态编译类 20 /// 2020-02-24 whz 21 /// </summary> 22 public class Compile 23 {
24 public static object Run(string methodName, string methodCode, object[] parametersObj) 25 { 26 try 27 { 28 StringBuilder sbCode = new StringBuilder(); 29 sbCode.AppendLine("using System; "); 30 sbCode.AppendLine("using System.IO; "); 31 sbCode.AppendLine("using System.Collections.Generic;"); 32 sbCode.AppendLine("using System.Linq;"); 33 sbCode.AppendLine("public class RuleClass{ "); 34 sbCode.AppendLine(methodCode); 35 sbCode.AppendLine("} "); 36 37 string code = sbCode.ToString(); 38 39 CSharpCodeProvider codeProvider = new CSharpCodeProvider(); 40 41 CompilerParameters compParameters = new CompilerParameters(); 42 compParameters.ReferencedAssemblies.Add(@"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5\System.Core.dll"); 43 compParameters.ReferencedAssemblies.Add(@"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5\System.XML.dll"); 44 compParameters.ReferencedAssemblies.Add(@"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5\System.Xml.Linq.dll"); 45 // Compile the code 46 CompilerResults res = codeProvider.CompileAssemblyFromSource(compParameters, code); 47 48 if (res.Errors.HasErrors) 49 { 50 StringBuilder error = new StringBuilder(); //create error info string 51 error.Append("编译有错误的表达式: "); //add the error text 52 foreach (CompilerError err in res.Errors) //traverse every compilation error that occurs 53 { 54 error.AppendFormat("{0}\n", err.ErrorText); //add error text ,line feed after each error 55 } 56 throw new Exception("编译错误: " + error.ToString());//抛出异常 57 } 58 59 // Create a new instance of the class 'MyClass' // 有命名空间的,需要命名空间.类名 60 object myClass = res.CompiledAssembly.CreateInstance("RuleClass"); 61 62 // Call the method 'PrintConsole' with the parameter 'Hello World' 63 // "Hello World" will be written in console 64 object result = myClass.GetType().GetMethod(methodName).Invoke(myClass, parametersObj); 65 //Console.WriteLine(" result = {0}", (decimal)result); 66 return result; 67 } 68 catch (Exception ex) 69 { 70 throw ex; 71 } 72 73 } 74 } 75 }
调用方式
//动态编译运行规则 并返回结果
object resul = DynamicCompileLib.Compile.Run(MethodName, MethodCode, objParam);
参数说明
string MethodName 方法名称
string MethodCode 方法逻辑规则
object[] objParam 参数数组。
浙公网安备 33010602011771号