关闭

C#中动态编译应用程序

707人阅读 评论(0) 收藏 举报

大家都知道,在ASP.NET中利用CodeBehind技术编写好的文件必须先通过编译,然后才能被执行。我们一般是在VS.NET中或者命令行下进行编译,那么现在的问题就是在程序中进行编译,也就是自己通过做好的规则动态生成一些程序源文件、然后对其进行编译。查看.Net Framework中提供的类库,发现了Microsoft.Csharp这个命名空间,其中有一个类Compiler。要调用这个类库必须先在引用中添加D:/WINNT/Microsoft.NET/Framework/v1.0.3705/cscompmgd.dll这个文件,这是我机器上的路径,各位根据自己机器所在路径设置吧。

仔细研究Compiler这个类:不需要初始化,直接可使用Compile方法,其中包含了5个参数。

string[] sourceTexts 源代码数组 其中每一个值包含一个文件中的源码

string[] sourceTextNames 源文件名数组 其中每一个值包含了一个文件名和上面的源代码数组中的值一一对应。

string target 输出的文件名

string[] imports 引用类库数组 也就是我们在VS.net中引用的那些类库的文件路径,一般都是dll文件,其中一个值表示一个引用文件。

IDictionary options 参数设置,实际上这也是一个数组,可以包含多个参数,具体的参数我在下面的部分会讲到。

 

实际这个Compile这个方法要求我们输入这些条件:

1、源代码——这个是必须的,没有源代码没法编译,那么源代码要求我们从程序文件中读取出来。

2、源文件的名称,和读取出的源代码一一对应。

3、编译输出的文件名,也可不填

4、引用的类库文件,如System.dll,System.data.dll这些都是经常会用到的。

5、其他参数设置

 

第一步:创建一个类及调用方法

首先我们创建一个Class

using System;

using System.IO;

using System.Text;

using Microsoft.CSharp;

 

namespace MyTest

{

private String[] filelist; //文件列表

private String[] cscode; //源代码

private String[] filename; //文件名

private String[] import; //引用类库

public class MyComplier()

{

 

//这里我做了一个简单的方法,要求用户输入两个参数,一个是文件夹的绝对路径

另外一个是输出的文件路径

public CompilerError[] MyCompile(String realpath,String output)

{

//……………………

}

 

}

}

那么下面我们会一步步来讲解如何实现这个方法。

 

第二步:读取程序文件列表

 

由于使用CodeBehind,那么实际上要编译的也就是扩展名为CS的文件。首先读取文件列表,制作一个方法用来读取目录下的文件路径:通过用户输入的绝对路径对文件进行整理搜索。

 

public String[] GetFileList(String realpath)//输入绝对路径

{

return System.IO.Directory.GetFiles(realpath,”*.cs”);//输入搜索条件

}

 

本方法将要编译的真实目录传递进入,然后返回目录下扩展名为CS的文件路径列表。那么读取文件的列表将会为文件中代码的获取及文件名的获取做准备。

 

第三步:读取程序文件内容

//这里我们调用了第二步建立的方法来获取文件列表

filelist= GetFileList(realpath); //获取文件路径列表

//根据文件的数量创建数组

cscode=new String[filelist.Length]; //建立源代码数组

String[] filename=new String[filelist.Length];//建立源文件名数组

//通过循环获取每个文件的信息每增加到对应的数组中

For (int I=0;I

{

String filepath= filelist. GetValue(i).ToString();//获取单个文件路径

cscode[I]= ReadTxtFile(filepath, Encoding.GetEncoding("GB2312"));//读取源文件中的代码、这里的编码为GB2312,也可设置为其他,这里调用的是我们下面创建的一个方法

filename[I]= System.IO.Path.GetFileName(filepath);//获取文件名

}

 

//读取文本文件内容

public String ReadTxtFile(String path,Encoding encode)

{

String str="";

try

{

if (File.Exists(path))

{

StreamReader sr=new StreamReader(path,encode);

str=sr.ReadToEnd();

sr.Close();

}

}

catch(IOException ex)

{Console.Write(ex.ToString());}

return str;

}

经过第二步之后我们已经满足了Compile方法所需的两个参数了,那么接下来将是对文件的输出及引用的一些配置。

 

第四步:配置输出文件名及路径

此处可根据你的需要,设置文件和路径,例如:E:/test/bin/test.dll String output=” E://test//bin//test.dll”;

这里我们根据用户输入的路径进行操作。

 

第五步:配置引用的类库文件

那么只要是你在程序引用到的类库,在此处都必须加入到数组中。

import=new String[10];//定义一个数组,数组长度根据你所需要引用的文件数量决定

import[0]="D://WINNT//Microsoft.NET//Framework//v1.0.3705//System.dll";

import[1]="D://WINNT//Microsoft.NET//Framework//v1.0.3705//IEHost.dll";

import[2]="D://WINNT//Microsoft.NET//Framework//v1.0.3705//System.Data.dll";

import[3]="D://WINNT//Microsoft.NET//Framework//v1.0.3705//System.Drawing.dll";

import[4]="D://WINNT//Microsoft.NET//Framework//v1.0.3705//System.Web.dll";

import[5]="D://WINNT//Microsoft.NET//Framework//v1.0.3705//System.Xml.dll";

import[6]="D://WINNT//Microsoft.NET//Framework//v1.0.3705//cscompmgd.dll";

上面的是我们经常用到的一些类库,除此之外,你自己编写的一些类库,如果也被引用到了,那么也必须增加到数组中。

 

第六步:进行属性参数配置

这里系统提供给了我们一个接口:Idictionary,这个接口可使用以下几个类来实现。

 

ListDictionary 使用单链接列表实现 IDictionary。建议用于通常包含 10 个或 10 个以下项的集合。

HybridDictionary在集合较小时,使用 ListDictionary 来实现 IDictionary,然后当集合变大时,切换到 Hashtable。

还有其他一些,我感觉用不上,这里就不讲了。那么,具体来看看:

 

System.Collections.IDictionary configs=new System.Collections.Specialized.ListDictionary();//实现这个接口

configs.Add("target","library"); //配置输出文件类型为库文件,这个参数是必须的

其中”target”为文件的格式属性,”library”为属性的值。

 

其他属性有:

addmodule 导入元数据 要包含在此程序集内的模块列表。模块名必须用竖线或管道字符分隔。值的类型必须是 String。

baseaddress 库的基址。值的类型必须是 Uint32

bugreport 产生错误报告文件。值的类型必须是 String。

checked 检查整数算法 设置默认表达式计算为选中(或未选中)。值的类型必须是 Boolean。

Debug发出调试信息 值的类型必须是 Boolean。不能指定“全部”或“pdbonly”。

Lib 指定程序集引用位置 查找模块和引用的程序集时要搜索的附加路径。值的类型必须是 String。

Unsafe启用不安全模式 允许不安全构造。值的类型必须是 Boolean

win32icon自动生成的 Win32 资源的 Win32 图标。值的类型必须是String

这里讲出主要的一些参数,还有一些由于用得比较少,那么就不一一列出了。

 

第七步:程序编译

CompilerError[] ce= Compiler.Compile(cscode,filename, output,import, configs);

那么实际上我们最后的编译也就是调用这个方法,此方法将会返回一个包含出错信息的数组。其中记录了编译过程中的出错信息,如果有错误信息返回,则编译无法通过。

 

最后我们将第一步中的方法整合:

 

public CompilerError[] MyCompile(String realpath,String output)

{

//……………………

通过上面的方法获取到参数,最后执行编译。

CompilerError[] ce= Compiler.Compile(cscode,filename, output,import, configs);

return ce;

}

 

到这里,基本上整个编译过程就完成了,大家可以在Aspx页面中调用或者在其他的类中调用,编译出来的效果和VS.net比起来一点不差,而且速度也非常快。大家甚至可以构建一个基于Web的简易的集成开发环境,当然这是后话了。

0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:2142次
    • 积分:35
    • 等级:
    • 排名:千里之外
    • 原创:0篇
    • 转载:3篇
    • 译文:0篇
    • 评论:0条
    文章分类
    文章存档