• 动态生成与编译(八)动态编译


     

    上次把实实在在的源代码生成了,不再是抽象的东西了,现在要用程序动态的来编译上次的东西。

    System.CodeDOM.Compiler中的三个接口都是从CodeDomProvider得到的(上次强调过了),这次用到的接口是ICodeCompiler,所以先:

                    CSharpCodeProvider provider = new CSharpCodeProvider();

               ICodeCompiler compiler = provider.CreateCompiler();

    这个接口的方法全是CompileAssemblyFrom*这种形式的,分别是*FromDom**FromFile**FromSource*,从此可以看出动态编译不只是从文件来编译,它可以直接从生成的CodeDOM直接编译,也可以从包含源代码的字符串编译(FromSource这个)。而且它可以一起编译好几个的,如CompileAssemblyFromDomBatch,当然也有*FileBatch之类的。

     

    编译与生成写法很象的,得到接口后就是一个*From*的方法也就好了。以CompileAssemblyFromFile为例:

    CompilerResults CompileAssemblyFromFile(
       CompilerParameters options,
       string fileName

    );

    也是一个参数作为源,这里就是fileName了;目的地,生成代码的时候是有个TextWrite类型的参数作为去向,而这里就是返回一个CompilerResults类型表示编译后的结果;在生成的时候有个CodeGeneratorOptions,这里也有一个options,只是类型不同而已,这里是CompileParameters,而编译的奥秘当然也就在这个CompileParameters里了。

     

    上面这个CompileParameters里设置的属性是很丰富,不过我没怎么玩过编译器,有些也不知道怎么跟编译时的哪个选项相对应。

    string CompilerOptions第一个就搁浅了,options这个概括太笼统,它说是附加的命令行参数,我不知道它是应该对应编译器选项里的哪些,难道是只要下面没有涉及过的选项都用这个来设吗?

    Evidence Evidence这个是证据,安全方面的东西,很少涉及,不太懂。

    bool GenerateExecutable是不是生成可执行文件,默认下是false,就是生成DLL文件。

    bool GenerateInMemory编译时在内存输出,默认情况下是不是的,都是输出到硬盘,大家大多也是这么干。要输出到内存设为true就是了。

    bool IncludeDebugInformation要不要生成调试信息,这没什么好说的。

    string MainClass主类的名称。

    string OutputAssembly输出程序集名称。

    StringCollection ReferencedAssemblies引用程序集的名称。

    TempFileCollection TempFiles临时文件。

    bool TreatWarningsAsErrors是否将警告视为错误。

    IntPtr UserToken创建编译器进程时的用户标记,这个不是很懂。

    int WarningLevel中止编译的警告等级。

    string Win32Resource要连接到已编译程序集中的Win32资源文件。

     

    可设置的属性是比较的多,但比起编译器的选项来好象还是有点小巫见大巫。看来很多东西是在刚开始的那个CompileOptions设置的。

     

    一般情况下很多属性都保持默认就是了,直接在构造函数里把最需要的东西设置出来就是了如下:

                    //编译参数

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

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

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

    上面的这个构造函数是全的构造函数了(再要设属性就只能new后再设置了)。第一个参数就是引用的程序集,第二个是输出文件名,第三个是要不要调试信息。

     

    再来一句:

    CompilerResults cr = compiler.CompileAssemblyFromFile(cp,filepath);

    编译结束。

     

    用那个文件或CodeDOM或一堆源代码的字符串编译成功了没有,可以从返回的那个CompilerResults来查看。这个CompileResults里也有好多东西可以查看的。

    CompiledAssembly 属性指示编译的程序集。

    Evidence 属性指示程序集的安全证据。

    PathToAssembly 属性指示编译的程序集的路径(如果不是只在内存中生成编译的程序集)。

    Errors 属性指示任何编译器错误和警告。

    Output 属性包含编译器输出消息。

    NativeCompilerReturnValue 属性指示编译器返回的结果代码值。

    TempFiles 属性指示编译和链接过程中生成的临时文件。

     

    这些都很简单的。至此编译的任务结束。

     

    动态生成与编译的基本的东西没了,主要的麻烦在生成CodeDOM上,难倒不难,就是长长的代码麻烦一点。生成源代码与动态编译基本没有什么亮点。

    不过下面还有个ICodeParser没有实现的,这里好象有点难度的,有点字符串分析的味道。前两天在CodeProject找到了一个,不过那个是两年前的代码,那时的Nunit跟现在的好象都不一样,我把它的单元测试部分拿掉才能编译通过。现在要分析一下它那个东西,不知有什么收获。

  • 相关阅读:
    luogu P1075 质因数分解
    luogu P1146 硬币翻转
    [HEOI2013]SAO
    [HAOI2010]软件安装
    [CodeForces-763C]Timofey and remoduling
    [CodeForces-375E]Red and Black Tree
    [CodeForces-178F]Representative Sampling
    [CodeForces-55D]Beautiful Numbers
    [AHOI2009]同类分布
    [ZJOI2010]数字计数
  • 原文地址:https://www.cnblogs.com/lichdr/p/62707.html
Copyright © 2020-2023  润新知