动态网站制作指南
[  QQ表情  ]
[ 投票调查 ]
[ 企业邮箱 ]
[ 网站空间 ]
网络编程 | 站长之家 | 网页制作 | 图形图象 | 操作系统 | 冲浪宝典 | 软件教学 | 网络办公 | 邮件系统 | 网络安全 | 认证考试 | 系统进程
ASP源码 | .Net源码 | PHP源码 | JSP源码 | JAVA源码 | CGI源码 | VB源码 | C++源码 | Delphi源码 | PB源码 | VF源码 | 汇编 | 服务器
电脑书籍下载:程序设计书籍 | 数据库教程书籍 | 平面与多媒体书籍 | 网络通讯书籍 | 系统管理书籍 | 网络安全书籍 | 认证考试书籍
Firefox | IE | Maxthon | 迅雷 | 电驴 | BitComet | FlashGet | QQ | QQ空间 | Vista | 输入法 | Ghost | Word | Excel | wps | Powerpoint
asp | .net | php | jsp | Sql | c# | Ajax | xml | Dreamweaver | FrontPages | Javascript | css | photoshop | fireworks | Flash | Cad | Discuz!
当前位置 > 网站建设学院 > 网络编程 > 软件工程
Tag:注入,存储过程,分页,安全,优化,xmlhttp,fso,jmail,application,session,防盗链,stream,无组件,组件,md5,乱码,缓存,加密,验证码,算法,cookies,ubb,正则表达式,水印,索引,日志,压缩,base64,url重写,上传,控件,Web.config,JDBC,函数,内存,PDF,迁移,结构,破解,编译,配置,进程
文章搜索服务
邮件订阅
输入你的邮件地址,
你将不会错过任何关于:
[ 软件工程 ]的信息

本月文章推荐
.模式与J2EE.
.Apache中的挂钩剖析(1).
.构建可“复用”的软件测试环境.
.高性能托管应用程序设计入门.
.为什么要用UML建模之建模的重要性.
.Tomcat中用web.xml控制Web应用详.
.VS2005改善团队开发的人力负担与.
.SOA成长五步走.
.DB2离线和在线全备、增量备份及恢.
.用UML描述Java类(1).
.建模的价值.
.在Avalon中建立数据识别的应用程.
.最先进的技术:Workflow Foundat.
.“6sigma”反面思维探讨.
.绩效管理实现“投资于人”.
.ERP失败的10大祸首.
.SOA引发中间件市场新变局.
.微软的软件开发管理哲学和spec文.
.Microsoft .NET让新一代因特网变.
.Project 2000进行项目管理(一).

.NET下的动态代码编译探索

文章类别:软件工程 | 发表日期:2008-3-23 |



  不能确定动态代码编译在什么地方是有意义的?一个普通情况就应该可以帮助阐明这个问题。假如你不得不从一个数据库中取出数据并将它放入另一个数据库。你应该只需使用一个SQL语句从源数据库中选取数据并插入目标数据库中,这只是小菜一碟,对不对?假如你正在拷贝生产数据以生成测试数据并需要改变数据以确保目标数据在以后开发中使用是安全的又将如何?你可能会构建一个数据传输系统(DTS)或某个其它传输机制,但是假如你这样做超过足够多的数据,这就会变成你每次为拷贝数据建立数据-擦除(data-scrubbing)机制而消耗时间。你可以写一个应用程序来加工并生成测试数据,但是每次你在一个不同的应用程序上用它时你都将不得不改动(应用程序)并创建新的算法。

  走进动态代码编译。胜于不停地写一些一次性的代码,你可以创建一个有特定内部运作机制的应用程序来传送数据并在传送时运用代码段来改变数据。该代码段将代理每个你需要在数据上要做的动作。它们将被作为原始文本被储存在一个数据库中或某个它们可以很轻易被修改的其它位置。代码段将被编译并在执行时同时应用到数据。这将答应你获得一个完全是不同的代码段的数据库,使得你可以很轻易地恢复、修改并应用它而不用每次都要改变你的应用程序的根本。

  这是个相当复杂的情况,但是它应该帮助你理解一些可能性。现在,让我们看看如何实现它。

  CodeCompileUnit(代码编译单元)

  为了动态编译一个类,从System.CodeDom命名空间的一个CodeCompileUnit开始。CodeCompileUnit包含一个程序图形。为了构建代码,你要创建一些支撑对象并将它们添加到CodeCompileUnit实例中去。这些对象:代表应该已经在你的代码中的,就像你预备在设计时要创建它的普通对象。

  . CodeNamespace—代表指定的命名空间

  . CodeTypeDeclaration—代表类型声明

  . CodeMemberMethod—代表一个方法

  一个HelloWorld例子

  你可以使用下面的示例代码来生成包含一个接收单个参数并返回一个值的SayHello方法的代码。scriptBody方法的参数值成为SayHello方法的实体(body)。你将你的代码包含在接收影响结果的参数的一个static(静态)类中以创建CodeCompileUnit。

public static CodeCompileUnit CreateExecutionClass(string typeNamespace,
string typeName,
string scriptBody)
{
 // 创建CodeCompileUnit以包含代码
 CodeCompileUnit ccu = new CodeCompileUnit(); // 分配需要的命名空间
 CodeNamespace cns = new CodeNamespace(typeNamespace);
 cns.Imports.Add(new CodeNamespaceImport("System"));
 ccu.Namespaces.Add(cns); // 创建新的类声明
 CodeTypeDeclaration parentClass = new CodeTypeDeclaration(typeName);
 cns.Types.Add(parentClass); // 创建获得一个参数并返回一个字符串的SayHello方法
 CodeMemberMethod method = new CodeMemberMethod();
 method.Name = "SayHello";
 method.Attributes = MemberAttributes.Public;
 CodeParameterDeclarationEXPression arg = new CodeParameterDeclarationExpression(typeof(string), "inputMessage");
 method.Parameters.Add(arg);
 method.ReturnType = new CodeTypeReference(typeof(string)); // 添加方法实体需要的代码
 CodeSnippetStatement methodBody =new CodeSnippetStatement(scriptBody);
 method.Statements.Add(methodBody);
 parentClass.Members.Add(method); return ccu;
}
CodeProvider(代码提供者)
  现在你已经创建了一个CodeCompileUnit包含你的代码段,使用它来生成被编译到你的动态程序集中去的全部源代码。下面的静态方法首先从前面的例子中调用方法并且同时使用CSharpCodeProvider生成全部代码:

public static string GenerateCode(string typeNamespace,
string typeName,
string scriptBody)
{
 // 调用我们前面的方法创建CodeCompileUnit
 CodeCompileUnit ccu = CreateExecutionClass(typeNamespace,
 typeName, scriptBody); CSharpCodeProvider provider = new CSharpCodeProvider();
 CodeGeneratorOptions options = new CodeGeneratorOptions();
 options.BlankLinesBetweenMembers = false;
 options.IndentString = "\t"; StringWriter sw = new StringWriter();
 try
 {
  provider.GenerateCodeFromCompileUnit(ccu, sw, options);
  sw.Flush();
 }
 finally
 {
  sw.Close();
 } return sw.GetStringBuilder().ToString();
}
  作为一个例子,用输入值:"CodeGuru.DynamicCode","ScriptType",和"return inputMessage;"调用GenerateCode方法得出以下输出:

//---------------------------------------------------------------
// <auto-generated>
// 该代码是由工具生成的。
// 运行时版本:2.0.50630.0
// 更改这个文件可能导致不正确的(程序)动作并且假如代码被再次生成时将会丢掉这些更改。
// </auto-generated>
//---------------------------------------------------------------
namespace CodeGuru.DynamicCode {
 using System;
 public class ScriptType {
  public virtual string SayHello(string inputMessage) {
   return inputMessage;
  }
 }
}
更多的请看:http://www.QQread.com/windows/2003/index.Html在内存中编译

  最后一步是获得生成的源代码并将它编译到一个当前的程序集中去。对于这个例子,你是将这个例子装入内存而不是一个物理文件。通过特定的编程语言提供者执行当前编译动作,在这个例程中就是CSharpCodeProvider。你设定任何预定的编译选项并从源代码编译这个程序集。

  下面的示例代码从你已构建的代码中生成了一个程序集:

static Assembly CompileInMemory(string code)
{
 CSharpCodeProvider provider = new CSharpCodeProvider(); CompilerParameters options = new  CompilerParameters();
 options.IncludeDebugInformation = false;
 options.GenerateExecutable = false;
 options.GenerateInMemory = true;
 CompilerResults results =provider.CompileAssemblyFromSource(options, code);
 provider.Dispose();
 Assembly generatedAssembly = null;
 if (results.Errors.Count == 0)
 {
  generatedAssembly = results.CompiledAssembly;
 }
 return generatedAssembly;
}
  如Assembly a = CompileInMemory(GenerateCode(typeNamespace, typeName, "return inputMessage;"));的调用将会生成一个新的程序集。你可能会用任何你想要的方法实体代替"return inputMessage;"来创建预定的变量作些并发调用。

  创建一个实例

  你已经动态生成了一个程序集并将其编译到内存中。下一个任务就是从程序集中创建一个类的实例。这实际上比听起来更加复杂。你已经创建的程序集存在于内存中。对它的存在没有任何参考信息,因此你不能简单的创建一个新的实例,因为它们不会解决问题。创建一个类以拥有所有已编译程序集作为一个工作区。你将不顾类型决定事件,所以当一个类型需要时你可以使用你的类型中的一个。 ExecutionHost示例代码

  下面的代码定义了一个名为ExecutionHost的类,它追踪了你所有的动态编译程序集:

using System;
using System.Collections;
using System.Reflection;
namespace CodeGuru.CodeDomSample
{
 class ExecutionHost
 {
  private Hashtable assemblies = null;
  public ExecutionHost()
  {
   assemblies = new Hashtable();
   // 响应类型解析事件(the type resolution event)要求以截取它并找到我们类型
   AppDomain.CurrentDomain.TypeResolve += new ResolveEventHandler(CurrentDomain_TypeResolve);
  }
  private Assembly CurrentDomain_TypeResolve(object sender,ResolveEventArgs args)
  {
   // 为预定的类型找出我们程序集
   Assembly a = null;
   if (assemblies.ContainsKey(args.Name))
   {
    a = (Assembly)assemblies[args.Name];
   }
   return a;
  } public void AddAssembly(string fullTypeName, Assembly a)
  {
   assemblies.Add(fullTypeName, a);
  } public string Execute(string typeFullName, string msg)
  {
   // 尝试创建触发事件所需要的类型
   Type targetType = Type.GetType(typeFullName, true, true);
   object target =targetType.Assembly.CreateInstance(typeFullName);
   IExecutableModule m = (IExecutableModule)target; return m.SayHello(msg);
  }
 }
}
namespace CodeGuru.CodeDomSample
{
 public interface IExecutableModule
 {
  string SayHello(string inputMessage);
 }
}
public static CodeCompileUnit CreateExecutionClass(string typeNamespace,string typeName,string scriptBody)
{
 // 创建CodeCompileUnit以存放代码
 CodeCompileUnit ccu = new CodeCompileUnit(); // 分配给预期的命名空间
 CodeNamespace cns = new CodeNamespace(typeNamespace);
 cns.Imports.Add(new CodeNamespaceImport("System"));
 ccu.Namespaces.Add(cns);
 // 创建类
 CodeTypeDeclaration parentClass = new CodeTypeDeclaration(typeName);
 cns.Types.Add(parentClass);
 // 新行-为IExecutableModule接口添加一个实现
 parentClass.BaseTypes.Add(typeof(CodeGuru.CodeDomSample.IExecutableModule));
 // 创建获得一个参数并返回一个字符串的SayHello方法
 CodeMemberMethod method = new CodeMemberMethod();
 method.Name = "SayHello";
 method.Attributes = MemberAttributes.Public;
 CodeParameterDeclarationExpression arg = new CodeParameterDeclarationExpression(typeof(string),
"inputMessage");
 method.Parameters.Add(arg);
 method.ReturnType = new CodeTypeReference(typeof(string));
 // 添加预期代码到方法实体
 CodeSnippetStatement methodBody = new CodeSnippetStatement(scriptBody);
 method.Statements.Add(methodBody);
 parentClass.Members.Add(method);
 return ccu;
}
  注重Execute方法。它用反射来创建预定类型的一个实例。这将触发_TypeResolve事件并答应你的程序集中的一个被返回,假如该被返回程序集通过AddAssembly方法已被添加到ExecutionHost中了。

  你也要注重在你的动态生成代码中添加的接口实现。没有它,你将不知道如何调用预期的方法。为了你的生成代码,IExecutableModule接口与作为一个基类添加的附加接口的CreateExecutionClass方法的一个最新副本一同被提供。

  另外,因为你增添了一个现在需要在CodeGuru.DynamicCode程序集内部使用的接口,你必须给含有IExecutableModule 声明的CodeGuru.CodeDomSample添加一个接口。请看下面最新的CompileInMemory副本:


static Assembly CompileInMemory(string code)
{
 CSharpCodeProvider provider = new CSharpCodeProvider();
 CompilerParameters options = new CompilerParameters();
 options.IncludeDebugInformation = false;
 options.GenerateExecutable = false;
 options.GenerateInMemory = true;
 // 新行-添加一个接口到需要的程序集
 options.ReferencedAssemblies.Add("CodeGuru.CodeDomSample.exe");
 CompilerResults results = provider.CompileAssemblyFromSource(options, code);
 provider.Dispose(); Assembly generatedAssembly = null;
 if (results.Errors.Count == 0)
 {
  generatedAssembly = results.CompiledAssembly;
 } return generatedAssembly;
}
  现在,你可以用下面的测试代码来测试动态生成一个程序集然后对方法做一个调用的端到端(end-to-end)过程:

string typeNamespace = "CodeGuru.DynamicCode";
string typeName = "ScriptType" + Guid.NewGuid().ToString("N");
Assembly a = CompileInMemory(GenerateCode(typeNamespace, typeName,"return inputMessage;"));
ExecutionHost host = new ExecutionHost();
string fullTypeName = typeNamespace + "." + typeName;
host.AddAssembly(fullTypeName, a);
string test = host.Execute(fullTypeName, "Hello World!");
  每次在你生成代码时使用Guid生成唯一对象名称。

  后记

  你已看完了一个非常基本的例子,它描述了一个复杂的主题及完成这个任务所需要的代码。在类型名称上添加Guid是为了确保其唯一性,因此你可以随心所欲地编译并使用各种不同的类型而不会在名称上发生冲突。你可以自由改变“return inputMessage”方法实体成为任何你喜欢的代码并试用之。你可以改变它,以使得所有关于方法实体的代码被存储在一个数据库中并在运行时重新获得。

上一篇:走出软件质量误区 人气:82
下一篇:软件开发方法述评 人气:126
点击此处浏览全部软件工程的内容 Dreamweaver插件下载 常用网页广告代码全集
  最新网站源码 最新软件下载
2008-5-16 乘风多用户PHP统计系统 v3.4
2008-5-16 轩溪下载系统 v3.78 build 0515
2008-5-16 普沙B2B 浙江省商贸网 v2.0
2008-5-16 asp抓蜘蛛的小程序 v1.0
2008-5-16 齐齐乐网私服发布站 仿haosf新版
2008-5-16 IssTech信息反馈系统 v1.0
2008-5-16 自由领域大头贴(js接口版) 修正版
2008-5-16 医院网站系统
2008-5-16 智拓-分类信息管理系统 v5.0
2008-5-7 Windows XP SP3 官方英文版
2008-5-7 Windows XP SP3 官方香港中文版
2008-5-7 Windows XP SP3 官方繁体中文版
2008-5-7 Windows XP SP3 官方简体中文版
2008-4-30 Multiple Unzip Wizard 1.02
2008-4-30 Multiple Unrar Wizard 1.0.0
2008-4-30 WinZip Install/Try/Uninstall a
2008-4-30 ZIP压缩文件修复器WzipFix 2.0
2008-4-30 Pentazip 6.01 Build 189 For Wi
  发表评论
姓 名: 验证码: [ 全部贴吧 ] [ 浏览评论 ]
内 容:
[ 汉字翻译拼音 ] [ 广告代码 ] [ 符号对照表 ] [ 进制转换 ] [ 经典小工具 ] [ 个税计算 ] [ 汉字简繁转换 ] [ 普通单位换算 ] [ 公制单位换算 ]
[ 生辰老黄历 ] [ 国内电话区号 ] [ 国家代码与域名缩写 ] [ 文字加密解密 ] [ 健康查询 ] [ 万年历 ] [ 手机号码查询 ] [ ip搜索 ] [ Google PR查询 ]
业务联系 | 广告刊登 | 频道合作 | 投稿荐稿 | 联系方式 | 加入收藏 | RSS订阅
Copyright © 2000-2008 www.knowsky.com All rights reserved | 网络实名:动态网站制作指南 | 沪ICP备05001343号