• 第12章 动态代码生成和编译技术


    第12章 动态代码生成和编译技术

    在后面的讨论中会涉及到一些关于动态代码生成的技术,因此,有必要先在这里对这个技术做一个介绍。

    关于动态代码生成和编译的技术,在Java和.Net中都有所支持。在Java平台之上,有JDK自己的tools.jar提供的功能,也可以通过一些第三方的字节码增强器来实现。但就这方面的技术来说,.Net提供的解决方案是最完整和成体系的。在这里,主要介绍.Net平台下的动态代码生成和编译技术。

    在.Net平台下,有两种技术来实现动态代码生成和编译,分别是Emit和CodeDom,下面,我们就这两种技术来做一些简单的介绍。

    12.1 Emit

    12.2 CodeDom

    CodeDOM的中文译名就是“代码文档对象模型”,使用这套模型,可以使编写源代码的程序的开发人员可以在运行时,根据表示所呈现代码的单一模型,用多种编程语言生成源代码,并且可以动态编译和运行所生成的代码。

    为表示源代码,CodeDOM 元素相互链接以形成一个数据结构(称为 CodeDOM 图),它以某种源代码的结构为模型。System.CodeDom 名称空间定义可以表示源代码的逻辑结构(与具体的编程语言无关)的类型。System.CodeDom.Compiler 名称空间定义从 CodeDOM 图生成源代码的类型,和在受支持的语言中管理源代码编译的类型。编译器供应商或开发人员可以扩展受支持语言的集合。

    .NET Framework 中包含了C#、JScript 和 Visual Basic 的代码生成器和代码编译器。开发人员也可以通过扩展System.CodeDom.Compiler 名称空间来实现自己的代码生成器和代码编译器。

    使用CodeDom来动态生成代码和编译的过程一般是:

    1. 使用CodeCompileUnit定义一个可编译的单元

    2. 使用CodeNamespace 定义一个名称空间,并把这个名称空间加入上面定义的可编译单元

    3. 使用CodeTypeDeclaration定义一个类,并把这个类加入上面定义的名称空间

    4. 使用CodeTypeMember的具体子类,例如CodeMemberField或者CodeMemberMethod为上面的类定义成员变量或者方法

    5. 使用CodeExpression定义某个方法中具体代码的调用


    6. 如果需要,可以通过某个具体的CodeDomProvider来生成源代码,例如,可以使用CSharpCodeProvider为上面的结构生成具体的C#代码。

    7. 通过CodeCompiler将上面的代码树编译成可执行的文件。

    下面的例子展示了使用CodeDom生成一个HelloWorld程序的例子。生成以后的代码应该是这个样子的:

    using System;

    namespace Sample

    {

        public class DemoClass

        {

        static void Main(string[] args)

         {

        System.Console.WriteLine("Hello World!");

        }

        }

    }

    生成程序的代码如下:

    public void GenerateCode()

    {

        //生成一个可编译的单元,这是最根部的东西

        CodeCompileUnit compunit = new CodeCompileUnit();

        //定义一个名为Sample的命名空间

        CodeNamespace sample = new CodeNamespace("Sample");

        compunit.Namespaces.Add(sample);

        sample.Imports.Add(new CodeNamespaceImport("System"));//导入System命名空间

        //定义一个名为DemoClass的类

        CodeTypeDeclaration MyClass = new CodeTypeDeclaration("DemoClass");

        sample.Types.Add(MyClass);

        //定义程序入口点,就是Main()

        CodeEntryPointMethod Start = new CodeEntryPointMethod();

        MyClass.Members.Add(Start);

        //下面产生调用方法的语句,//这句会产生如下的C#代码System.Console.WriteLine("Hello World!");

        CodeMethodInvokeExpression cs = new CodeMethodInvokeExpression

        (new CodeTypeReferenceExpression("System.Console"),

        "WriteLine", new CodePrimitiveExpression("Hello World!"));

        Start.Statements.Add(cs);

        //根据CodeDOM产生程序代码,代码文件就是DemoClass.cs,这里生成C#代码 

        CSharpCodeProvider cprovider = new CSharpCodeProvider();

        ICodeGenerator gen = cprovider.CreateGenerator();

        StreamWriter sw = new StreamWriter("DemoClass.cs", false);

        gen.GenerateCodeFromCompileUnit(compunit, sw, new CodeGeneratorOptions());

        sw.Close();

        //编译源代码

        ICodeCompiler compiler = cprovider.CreateCompiler();

        //编译参数

        CompilerParameters cp = new CompilerParameters(new string[] { "System.dll" },

        filepath.Substring(0, filepath.LastIndexOf(".") + 1) + "exe", false);

        cp.GenerateExecutable = true;//生成EXE,不是DLL

        CompilerResults cr = compiler.CompileAssemblyFromDom(cp, compunit);

    }

    上面只是一个很简单的例子,通过CodeDom,可以生成任何复杂的程序。
  • 相关阅读:
    【分布式事务】的一篇良心之作!
    如何保证缓存与数据库的数据一致性
    30多岁的大龄程序员,应该如何保持职场竞争力
    Kafka acks参数对消息持久化的影响
    Kafka 如何优化内存缓冲机制造成的频繁 GC 问题?
    Shell中的特殊符号(special characters)和含义
    Bash中的一些常用的数组相关的特殊语法(array syntax)
    一站式搞定Bash脚本的参数处理问题
    Bash脚本set命令教程
    Bash中的eval命令
  • 原文地址:https://www.cnblogs.com/twttafku/p/943614.html
Copyright © 2020-2023  润新知