c#动态编译,动态生成程序集

首先引入命名空间

using System.CodeDom.Compiler;


 

其次我们要了解CSharpCodeProvider这个类是用于动态编译c#程序集,它继承了ICodeCompiler

 在使用动态编译前,应该先了解反射的相关知识

 

在动态编译时,提供了多种方式如下:

CompileAssemblyFromDom
使用指定的编译器设置从指定的 CodeCompileUnit 所包含的 System.CodeDom 树中编译程序集。
CompileAssemblyFromDomBatch
基于包含在 CodeCompileUnit 对象的指定数组中的 System.CodeDom 树,使用指定的编译器设置编译程序集。
CompileAssemblyFromFile
从包含在指定文件中的源代码,使用指定的编译器设置编译程序集。
CompileAssemblyFromFileBatch
从包含在指定文件中的源代码,使用指定的编译器设置编译程序集。
CompileAssemblyFromSource
从包含源代码的指定字符串,使用指定的编译器设置编译程序集。
CompileAssemblyFromSourceBatch
从包含源代码的字符串的指定数组,使用指定的编译器设置编译程序集。

 

在编译时,我们可以选择是exe或dll。当然,我们也可以只在内存编译,不用生成文件,程序集用完就可以释放。

下面是一个实例

using System;
using Microsoft.CSharp;
using System.CodeDom.Compiler;
using System.CodeDom;

namespace PG
{
    class Program
    {
        static void Main(string[] args)
        {
            // 创建编译器对象
            CSharpCodeProvider p = new CSharpCodeProvider();
            ICodeCompiler cc = p.CreateCompiler();

            // 设置编译参数
            CompilerParameters options = new CompilerParameters();
            options.ReferencedAssemblies.Add("System.dll");
            options.GenerateExecutable = true;
            options.OutputAssembly = "HelloWorld.exe";

            //options.ReferencedAssemblies.Add("System.Windows.Forms.dll");
            //options.EmbeddedResources.Add("Data.xml"); // 添加内置资源
            //options.CompilerOptions += " /target:winexe";
            //options.CompilerOptions += " /res:Resource1.res";
            //options.CompilerOptions += " /win32icon:test.ico";

            // 创建源码

            // 1. 使用CodeDom创建源码
            //CodeCompileUnit cu = new CodeCompileUnit();
            //CodeNamespace Samples = new CodeNamespace("Samples");
            //cu.Namespaces.Add(Samples); 
            //Samples.Imports.Add(new CodeNamespaceImport("System"));             
            //CodeTypeDeclaration Class1 = new CodeTypeDeclaration("Class1"); 
            //Samples.Types.Add(Class1); 
            //CodeEntryPointMethod Start = new CodeEntryPointMethod(); 
            //CodeMethodInvokeExpression cs1 = new CodeMethodInvokeExpression(  
            //    new CodeTypeReferenceExpression("System.Console"), "WriteLine", 
            //    new CodePrimitiveExpression("Hello World!") );
            //Start.Statements.Add(new CodeExpressionStatement(cs1));
            //Class1.Members.Add(Start); 

            // 2. 直接指定源码字符串
            string code = @"
                using System;
                namespace Samples
                {
                    public class Class1
                    {
                        static void Main(string[] args)
                        {
                            Console.WriteLine(""Hello, World!"");
                            Console.WriteLine(DateTime.Now.ToString());
                        }
                    }
                }
            ";
            CodeSnippetCompileUnit cu = new CodeSnippetCompileUnit(code);

            // 开始编译
            CompilerResults cr = cc.CompileAssemblyFromDom(options, cu);

            // 显示编译信息
            if (cr.Errors.Count == 0)
                Console.WriteLine("/"{0}/" compiled ok!", cr.CompiledAssembly.Location);
            else
            {
                Console.WriteLine("Complie Error:");
                foreach (CompilerError error in cr.Errors)
                    Console.WriteLine("  {0}", error);
            }

            Console.WriteLine("Press Enter key to exit...");
            Console.ReadLine();
        }

    }
}


 

下面我们来换成内存编译,用CompileAssemblyFromSource来编译

using System;
using System.Reflection;
using System.Globalization;
using Microsoft.CSharp;
using System.CodeDom;
using System.CodeDom.Compiler;
using System.Text;

namespace ConsoleApplication1
{
    public class Program
    {
        static void Main(string[] args)
        {
            // 1.CSharpCodePrivoder 
            CSharpCodeProvider objCSharpCodePrivoder = new CSharpCodeProvider();

            // 2.ICodeComplier 
            ICodeCompiler objICodeCompiler = objCSharpCodePrivoder.CreateCompiler();

            // 3.CompilerParameters 
            CompilerParameters objCompilerParameters = new CompilerParameters();
            objCompilerParameters.ReferencedAssemblies.Add("System.dll");
            objCompilerParameters.GenerateExecutable = false;
            objCompilerParameters.GenerateInMemory = true;

            // 4.CompilerResults 
            CompilerResults cr = objICodeCompiler.CompileAssemblyFromSource(objCompilerParameters, GenerateCode());

            if (cr.Errors.HasErrors)
            {
                Console.WriteLine("编译错误:");
                foreach (CompilerError err in cr.Errors)
                {
                    Console.WriteLine(err.ErrorText);
                }
            }
            else
            {
                // 通过反射,调用HelloWorld的实例 
                Assembly objAssembly = cr.CompiledAssembly;
                object objHelloWorld = objAssembly.CreateInstance("DynamicCodeGenerate.HelloWorld");
                MethodInfo objMI = objHelloWorld.GetType().GetMethod("OutPut");

                Console.WriteLine(objMI.Invoke(objHelloWorld, null));
            }

            Console.ReadLine();
        }

        static string GenerateCode()
        {
            StringBuilder sb = new StringBuilder();
            sb.Append("using System;");
            sb.Append(Environment.NewLine);
            sb.Append("namespace DynamicCodeGenerate");
            sb.Append(Environment.NewLine);
            sb.Append("{");
            sb.Append(Environment.NewLine);
            sb.Append("    public class HelloWorld");
            sb.Append(Environment.NewLine);
            sb.Append("    {");
            sb.Append(Environment.NewLine);
            sb.Append("        public string OutPut()");
            sb.Append(Environment.NewLine);
            sb.Append("        {");
            sb.Append(Environment.NewLine);
            sb.Append("             return /"Hello world!/";");
            sb.Append(Environment.NewLine);
            sb.Append("        }");
            sb.Append(Environment.NewLine);
            sb.Append("    }");
            sb.Append(Environment.NewLine);
            sb.Append("}");

            string code = sb.ToString();
            Console.WriteLine(code);
            Console.WriteLine();

            return code;
        }
    }
}


 

 

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
C# 动态编译可以让我们在运行时动态编译代码并生成可执行程序。这在某些情况下非常有用,例如在我们需要根据用户输入来生成代码的情况下。 以下是一个简单的示例,演示了如何使用 C# 动态编译: ```csharp using System; using System.CodeDom.Compiler; using System.Reflection; using Microsoft.CSharp; class Program { static void Main() { // 定义代码片段 string code = @" using System; namespace MyNamespace { public class MyClass { public static void SayHello() { Console.WriteLine(""Hello, World!""); } } }"; // 编译代码 CSharpCodeProvider provider = new CSharpCodeProvider(); CompilerParameters parameters = new CompilerParameters(); parameters.GenerateInMemory = true; CompilerResults results = provider.CompileAssemblyFromSource(parameters, code); // 检查是否有编译错误 if (results.Errors.HasErrors) { Console.WriteLine("编译错误:"); foreach (CompilerError error in results.Errors) { Console.WriteLine(error.ErrorText); } return; } // 从程序中获取类和方法 Assembly assembly = results.CompiledAssembly; Type type = assembly.GetType("MyNamespace.MyClass"); MethodInfo method = type.GetMethod("SayHello"); // 调用方法 method.Invoke(null, null); } } ``` 该示例中,我们首先定义了一个字符串变量 `code`,其中包含要编译的代码片段。然后使用 `CSharpCodeProvider` 类创建一个编译器实例,并使用 `CompileAssemblyFromSource` 方法将代码编译程序。我们还需要指定 `CompilerParameters`,其中包括一些编译选项,例如是否将程序生成到内存中。 如果编译成功,则可以通过程序中的 `GetType` 方法获取类的类型,并使用 `GetMethod` 方法获取类中的方法。最后,使用 `Invoke` 方法调用该方法,并在控制台输出 "Hello, World!"。 需要注意的是,动态编译可能存在安全性问题,因为用户可以利用它来注入恶意代码。因此,在使用动态编译时,需要进行严格的输入验证和安全性检查。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值