CodeDOM 系列一: 初识

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CodeDOM 系列一: 初识相关的知识,希望对你有一定的参考价值。

最近手头项目接触到了CodeDom,顺带着在这里做个系列文章,有兴趣的可以做个参考。
 
CodeDOM是个用于运行时生成代码,以及编译生成的代码的相关技术。我们通过构造CodeDOM这样的DOM树 来自动生成代码。
和反射都属于动态编程相关的技术。我们知道反射用的比较多的地方在于各种框架,在运行时创建实例以及相关操作。那CodeDOM有哪些用途呢?
MSDN---

CodeDOM 的一些一般用途包括:

  • 模板化代码生成:生成 ASP.NET、XML Web 服务客户端代理、代码向导、设计器或其他代码发出机制的代码。

  • 动态编译:支持以一种或多种语言进行代码编译。
     
    动态编译我们怕是没什么机会接触了,那就剩下第一种可能。第一种用途也说的很含糊,我们暂且不管,code起来再说。
    我们以一个简单的例子做解释
 class Program
    {

        //codedom 这种东西 是用来自动生成代码的,而生成什么样的代码就依靠我们提供的codeDom代码树,这个名词很类似于html Dom,也就是
        //我们编好 codedom结构树,他会帮我们什么代码。(好像理所当然的感觉) 至于生成什么样的语言的代码,则要看所提供的不同的provider.
        
        static void Main(string[] args)
        {
            
            GenerateCode(); //先生成,这时候 文件已经生成了
            CompilerResults results = CompileCode("generatedHelloWorld.cs"); //在编译我们生成的cs文件           
            Console.ReadKey();
        }

        //构造dom树 创建编译单元.这一步是我们写代码的主体
        public static CodeCompileUnit createCompileUnit()
        {
            CodeCompileUnit compileUnit = new CodeCompileUnit();
            //开始构造最简单的代码树, 先把各个节点创建出来 再关联他们之间的关系。
            //命名空间
            CodeNamespace ns = new CodeNamespace("Demo");
            //类名
            CodeTypeDeclaration typename = new CodeTypeDeclaration("Test");
            //定义一个main入口方法
            CodeEntryPointMethod entry = new CodeEntryPointMethod();
            //在main方法里面输出console.writeline(helloworld);
            CodeMethodInvokeExpression expression_1 = new CodeMethodInvokeExpression(
                new CodeTypeReferenceExpression("System.Console"),
                "WriteLine",
                new CodePrimitiveExpression("Hello world! This is auto generated code ,Congratulations!")
                );
            //再输出一句console.readkey();
            CodeMethodInvokeExpression expression_2 = new CodeMethodInvokeExpression(
                new CodeTypeReferenceExpression("System.Console"),
                "ReadKey"
                );

            //连接节点
            compileUnit.Namespaces.Add(ns);
            ns.Imports.Add(new CodeNamespaceImport("System"));
            ns.Types.Add(typename);
            typename.Members.Add(entry);
            entry.Statements.Add(expression_1);
            entry.Statements.Add(expression_2);
            return compileUnit;

        }

        //重要的对象就是 generator compiler 以及parser
        //根据创建的编译单元 生成代码
        public static void GenerateCode()
        {
            //用于生成C#代码的provider
            CSharpCodeProvider provider = new CSharpCodeProvider();
            ICodeGenerator generator = provider.CreateGenerator();
            StreamWriter writer = new StreamWriter("generatedHelloWorld.cs",false);
            generator.GenerateCodeFromCompileUnit(createCompileUnit(),writer,new CodeGeneratorOptions());
            writer.Close();
        }

        //编译自动生成的源码
        public static CompilerResults CompileCode(string filepath)
        {
            CSharpCodeProvider provider = new CSharpCodeProvider();
            ICodeCompiler compiler = provider.CreateCompiler();
            //我们还需要提供一些编译所需要的参数
            CompilerParameters paras = new CompilerParameters(new string[]{"System.dll"},"HelloWorld.exe",false);
            paras.GenerateExecutable = true;
            CompilerResults results = compiler.CompileAssemblyFromFile(paras,filepath);
            return results;
        }
    }

步骤其实并不复杂,就是 拼接compileUnit树, 根据树生成.cs文件,编译生成的文件。在运行我们上面的程序之后 发现,文件夹多了一些东西

 

技术分享

就是我们生成的文件,运行HelloWorld.exe

技术分享

 

很开森有木有!看来和CodeDom初识还是愉悦的~

 

 

以上是关于CodeDOM 系列一: 初识的主要内容,如果未能解决你的问题,请参考以下文章

初识Spring源码 -- doResolveDependency | findAutowireCandidates | @Order@Priority调用排序 | @Autowired注入(代码片段

初识Spring源码 -- doResolveDependency | findAutowireCandidates | @Order@Priority调用排序 | @Autowired注入(代码片段

CodeDom

如何在 codedom 编译的代码中调试/中断

初识 Node.js 丨path 路径模块

Reflection.Emit 与 CodeDOM