C#动态编译与执行代码

最近在项目中遇到一个这样的需求,要求规则动态变化,并且用户可以自定义,经查多种资料 ,可以用动态运行类来实现。

在此之前,我们先来了解几个类型,方法及属性,CSharpCodeProviderICodeCompilerCompilerParametersCompilerResultsAssembly。。

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 参数数组。

 

posted on 2020-04-03 11:14  #知了  阅读(1)  评论(0)    收藏  举报