文档章节

.Net开发笔记(八) 动态编译

IT周见智
 IT周见智
发布于 2015/06/05 17:18
字数 2498
阅读 6
收藏 1
点赞 0
评论 0

虽然标题为“动态编译”,其实本文包含两个部分,一个就是标题说的动态编译源代码,另外一个应该是动态生成源代码。也就是说,在.Net中可以存在这样一种情况:在程序运行期间,由程序控制动态生成一份源代码(Source Code),然后再编译该源代码,生成一个新的程序集,紧接着再加载生成的程序集,最后运行。这个情况可能出现在很多地方,比如一些模板代码生成,像asp.net页面生成html,还可以在程序运行期间,由用户控制,动态的扩展程序功能。

要了解以上的实现过程,需先了解以下几个知识点:

  1. 反射
  2. 跨应用程序域(AppDomain)访问支持
  3. CodeDOM(代码文档对象模型)

我大概介绍一下后面两个,反射我就不说什么了,想必诸位都清楚,文章最后我会展示一下我做的一个Demo,主要有两个功能,动态编译代码和仿aspx页面生成html,功能很简单做工也很粗糙,但大概的原理过程都有,提供原程序下载,源程序注释都很详细,下下来就能看懂。

AppDomain(应用程序域):

先引用MSDN上的一句话:应用程序域(由 AppDomain 对象表示)为执行托管代码提供隔离、卸载和安全边界。是个什么意思呢?说得概括直白一点,就是它相当于一个容器,存放一些数据和其他资源,每个AppDomain都有自己的范围,各管各的事情,我们在将源代码(Source Code)动态编译成程序集后,还需要把它加载,最后运行,不然的话,动态编译就没什么意义了,想必各位清楚,在咱们学习“反射”的时候就知道用Assembly.Load()类似这样的方法加载程序集,然后创建实例(Instance),然后取得它的Type进行操作等等,但是如果按以上这样的方法加载的程序集的话,它默认被加载到当前AppDomain中(此当前AppDomain就是指程序一开始运行系统自动为其创建的一个AppDomain),又由于程序集不能单独卸载,也就是说加载进来之后的程序集会一直存在该AppDomain中,你如果加载的次数不多,这也就无所谓,但是如果像我们今天遇到的情况,需要反复不停的编译源代码,将生成的程序集加载运行的话,问题就出现了,最后加载进来的程序集就会越来越多,最后内存不足(Leak Memory),解决的办法就是,将每次用完的程序集卸载掉,目前卸载程序集的办法只有(我了解到的)卸载程序集所在的AppDomain,容器玩完了,容器里面的东西肯定也玩完了,但程序集如果一开始就加载到当前AppDomain中的话,问题就来了,因为当前AppDomain是不能被卸载的(如果当前AppDomain卸载了,什么都玩完了,怎么会有后续),所以,一开始加载程序集的时候,就不应该将其加载到当前AppDomain,这就需要我们新创建一个AppDomain,专门用来存放加载进来的程序集,一旦使用完毕后,马上将其卸载。创建新的AppDomain、跨域访问等具体操作,请看源代码。

CodeDOM(代码文档对象模型):

如果诸位知道DOM的话,这个其实很好理解,它两意思差不多,我们在处理html代码(XML)的时候,将它的各个节点都当做一个“对象”(Object),<Body></Body>、<Title></Title>等等,都是对象,在构建一个html文档的时候,我们可以先创建根,然后创建它的各个子节点,再然后设置各个子节点的属性、文本什么的,打个比方:HtmlHTML html = new HtmlHTML();HtmlHEAD head = new HtmlHead(); html.Childs.Add(head);创建两个节点对象,将一个加入到另外一个的子节点中去。.Net中System.Xml命名空间中有很多操作XML的类型,比如XmlAttribute、XmlElement、XmlComment等等,每一个类都代表XML文档中的一个节点元素,构建一个xml文档的时候,也是将一个加到另外一个的子节点集合中去,然后设置各个元素的其他属性等等,大概操作基本都这样。网上摘抄一段代码如下:

View Code
 1 XmlText xmltext; 
 2          XmlDocument xmldoc = new XmlDocument(); 
 3 
 4         //加入XML的声明段落 
 5          XmlNode xmlnode = xmldoc.CreateXmlDeclaration("1.0", "gb2312", null); 
 6          xmldoc.AppendChild(xmlnode); 
 7 
 8         //加入一个根元素 
 9          XmlElement xmlelem = xmldoc.CreateElement("", "bookstore", ""); 
10          xmltext = xmldoc.CreateTextNode(""); 
11          xmlelem.AppendChild(xmltext); 
12          xmldoc.AppendChild(xmlelem); 
13 
14         //加入一个子元素 
15          XmlElement xmlelem1 = xmldoc.CreateElement("", "book", ""); 
16          xmltext = xmldoc.CreateTextNode(""); 
17          xmlelem1.AppendChild(xmltext); 
18         //为子元素"book"增加两个属性 
19          xmlelem1.SetAttribute("genre", "", "fantasy"); 
20          xmlelem1.SetAttribute("ISBN", "2-3631-4"); 
21          xmldoc.ChildNodes.Item(1).AppendChild(xmlelem1);

如上所述,构建一个xml文档的代码。那么,CodeDOM就可以类比了,把什么命名空间(namespace)、类(Class)、引用(using)、方法(Method)、事件(Event)、赋值语句(AssignStatement)、异常捕获(TryCatchFinallyStatement)等等都当做对象,如果你仔细观察,发现其实程序源代码(Source Code)的结构跟html、xml等都是一样一样的,一层嵌套着另外一层,既然一样,那么我们构造一个源程序文档的方法肯定也是和构造DOM结构文档一样。

另外,像XmlAttribute、XmlComment、XmlNode这样的类型存在System.Xml命名空间中,那么CodeDOM中的各个类型存在哪儿呢?.Net中为我们提供的这些类型在System.CodeDOM这个命名空间中,基本上源程序中各个结构都能在这个命名空间中找到对应的类型。

到此,我们知道了利用System.CodeDOM中的类型动态的构造源代码,那么怎么将构造完的源代码保存下来(生成文本格式的代码,保存成源文件)?以及怎么将其编译,生成最终可以运行的程序集?.Net中又为我们提供了专门用于生成源代码和编译源代码的类,它们存在System.CodeDOM.Compiler命名空间中,具体要使用其中的两个接口ICodeCompiler和ICodeGenerator,它们两个的C#和VB版的具体实现类存在Microsoft.CSharp命名空间和Microsoft.VisualBasic命名空间。生成源代码和编译源代码操作都会返回执行结果,可以在返回结果中查看相关信息,比如编译源代码时,可以查看编译错误。

现在我们已经清楚了整个流程,来张图说明一下:

图1

做的一个Demo

做的这个Demo中其实并没有使用到上图中的第2步和第3步,因为不需要动态生成源码,取而代之的是让用户直接输入源码,然后将输入的源码拿来编译执行,或者先将aspx页面代码(html和C#的混合体)解析成代码片段,然后拿来编译执行。也就是说,Demo中的流程应该是这样的:

图2

源码注释很详细,我就在这不贴了。再来两张效果图:

图3

图4

图5

源码C#部分XP .net3.5测试通过,VB部分没测试。

下载地址:http://download.csdn.net/detail/xiaozhi_5638/5172507

希望有帮助O(∩_∩)O~,如果觉得本文对您有用,请点击一下右下方的“赞”或者给个评论建议,非常感谢!!!

题外话:

    昨晚上跟b哥谈论一件衣服,一起回忆起了我大学时期的着装,无袖T恤+长短裤+ 人字拖,现在想想,甚是现世,不知不觉惭愧起来,责备自己年少不懂事,乱了校 规伤了风化。高三时,穿过一段时间的木屐+大裤衩,不知wy君是否还记得起?自认为学生时代没有给老师留下好的印象,学习成绩即不很突出,也不是老师眼中的乖乖娃,高中上语文时看物理,上物理课时看英语,被老师发现无数次,没办法,后来我一跟别人说我是偏科生,问哪科,答曰数学,无比脸红,丢尽了无数理科生的 脸,后来高考马马虎虎,读了一个二流大学,大一规规矩矩,大二开始翘课抄作业 ,即影响校容也丢了现代青年应有的颜面,谈来惭愧,不提也罢。有时候在讲一个 人过去是怎么“作恶多端”,并不是想衬托TA现在有多大进步,或者炫耀TA有一个 多么“拉风”的青春,这就像现在许多人讲自己出生如何贫寒,起跑线比别人多么 靠后,条件如何艰苦,但TA还是一直会坚持下去,他相信自己是个潜力股,说到这,无比骄傲,其实殊不知,出生贫寒并不是优势,起跑线落后更不是资本, 你说你是“潜力股”,吁,“潜力股”好多时候也许只是安慰那些有着弱小心灵的屌丝,不是吗,跑题了。其实我本人倒是一直推崇做事做完了就完了,不要总是回过头 去想它对不对,更要避免耿耿于怀,但学生时代的所作所为,有时候的确让我不安 ,觉得愧对各位老师,也许他们根本记不起,但还是在此道个不是,虽然我现在并 不是老师,也没有身兼“传道授业解惑者”这样的职业。《单车》中有句歌词“经 已给我怎会看不到,虽说演你角色实在有难度”,虽然角色不同,意义大概一样吧 。

© 著作权归作者所有

共有 人打赏支持
IT周见智

IT周见智

粉丝 10
博文 61
码字总数 185891
作品 0
西青
Cocos2dx游戏开发系列笔记9:android手机上运行《战神传说》,并解决横竖屏即分辨率自适应

上节说到cygwin下成功编译出so文件,下面我们要把游戏运行在android上。 开始干活! 其实步骤可以参考 Cocos2dx游戏开发系列笔记6:怎样让《萝莉快跑》的例子运行在vs和手机上 1 用eclipse打...

懒骨头
2013/12/09
0
0
大前端 Android 开发日记七:MPAndroidChat 填坑笔记

大前端 Android 开发日记七:MPAndroidChat 填坑笔记 Blog | Phodal Geek's Life2017-12-241 阅读 Android 继续上一天的 MPAndroidChat 填坑记录。 MPAndroidChat 自定义 Marker 首先,是自定...

Blog | Phodal Geek's Life
2017/12/24
0
0
Android-开发姿势

Android 攻城狮—全套必备神级工具(开发,插件,效率) 如果你有用的酸爽的软件,请下面留言。我会持续更新。。。 “替你” 总结的 Gradle 配置 关于 Gradle 配置的一些总结,欢迎交流! 常...

掘金官方
2017/12/28
0
0
大前端 Android 开发日记八:Android 短信、微信、微博分享

大前端 Android 开发日记八:Android 短信、微信、微博分享 Blog | Phodal Geek's Life2017-12-241 阅读 Android 在纠结了几天的图表功能之后,我开始开发一个新的功能。即分享内容到短信、微...

Blog | Phodal Geek's Life
2017/12/24
0
0
KVM虚拟化学习笔记系列文章列表

kvm虚拟化学习笔记(一)之kvm虚拟化环境安装 http://koumm.blog.51cto.com/703525/1288795 kvm虚拟化学习笔记(二)之linux kvm虚拟机安装 http://koumm.blog.51cto.com/703525/1289627 kvm虚拟...

蓝狐乐队
2015/03/19
0
0
Cocos2dx游戏开发系列笔记1:一个崭新的开始,cocos2dx2.2+ndkr9+Cygwin

Android开发者做cocos2dx最大的绊脚石,不是c++,而是环境的搭建... 骨头也是费了半天劲才终于在真机上看到了那个类似猕猴桃的头,这里简单记录一下。 环境:(算比较新了2013.11.17) coco...

懒骨头
2013/12/09
0
0
MAVEN 学习笔记

一、MAVEN是什么? maven将自己定位为一个项目管理工具。它负责管理项目开发过程中的几乎所有的东西: 版本——maven有自己的版本定义和规则 构建——maven支持许多种的应用程序类型,对于每...

lizo
2016/12/04
20
0
Yocto开发相关笔记

Yocto开发相关笔记 添加一个新的machine 添加一个新的machine需要在新加layer的conf/machine/目录中填写对应的配置文件,比如:raspberrypi3.conf是树莓派3的配置文件。该配置文件位于meta-...

linuxhunter
2016/08/22
1K
0
Google发布Chrome 63 beta:支持动态模块导入

Google 近日向全平台推送了 Chrome 63 的 beta 版本,而我们可以预见下个月的正式版都将迎来哪些变动。对开发者来说,Chrome 63 带来了诸多改进,比如动态模块导入、新增设备内存 API、改进权...

稿源:
2017/10/30
0
0
Groovy学习笔记(1)-简介

Groovy是一种基于JVM(Java虚拟机)的面向对象的敏捷动态语言,它结合了Python、Ruby和Smalltalk的许多强大的特性(比如动态类型转换、闭包和元编程(metaprogramming)支持),Groovy 代码能...

山海经
2016/11/09
37
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

TensorFlow 线性回归 拟合

用tf 对 一次函数进行拟合 效果 loss 简单实现如下 import tensorflow as tfimport numpy as npimport matplotlib.pyplot as plt# 保存显示数据plotdata = {"batchsize": [], "los...

阿豪boy
5分钟前
0
0
JupyterLab安装地图插件

JupyterLab安装地图插件 (本文所述软件还在发展之中,欢迎加入开源项目,提供建议、测试和开发。) 在Jupyter中进行数据分析时,往往需要将数据叠加到地图上。简单的可以利用matplotlib/ec...

openthings
13分钟前
0
0
Coding and Paper Letter(八)

资源整理 1 Coding: 1.Python项目,由Allen Downey撰写的Think Python第二版的LaTeX源代码和支持代码。 ThinkPython2 2.R语言包h3jsr,h3jsr使用V8的神奇力量通过其javascript绑定提供对Ube...

胖胖雕
22分钟前
0
0
skiplist跳跃表

插入删除log(N) TODO

梦想游戏人
23分钟前
1
0
利用世界杯,读懂 Python 装饰器

Python 装饰器是在面试过程高频被问到的问题,装饰器也是一个非常好用的特性, 熟练掌握装饰器会让你的编程思路更加宽广,程序也更加 pythonic。 今天就结合最近的世界杯带大家理解下装饰器。...

p柯西
37分钟前
0
0
Xshell登录阿里云服务器ECS

Xshell登录阿里云服务器ECS 1. 参考资料: 1). 《阿里云服务器怎么用?阿里云服务器使用教程》 链接:http://www.cr173.com/html/50758_1.html 2). eagle-zhang的CSDN博客《Xshell连接不上阿...

SuShine
46分钟前
1
0
IDEA中的HTTP Client Editor测试API

在前后端分离项目,前后端通过api进行通信。如果用postman免费版进行api测试的话,由于无法保存测试脚本到文件,不方便前端查看。 你可以选择付费版。也可以利用IDEA自带的HTTP Client Edito...

hutaishi
49分钟前
0
0
解决“只能通过Chrome网上应用商店安装该程序”的方法

摘要 : 最近有些用户反映某个Chrome插件在安装的时候,提示“只能通过Chrome网上应用商店安装该程序”,为了解决这一问题,Chrome插件网带来了相关的解决方法。 某些用户在Chrome插件网下载了...

沧海一刀
50分钟前
0
0
通过UNIX域套接字传递文件描述符

  传送文件描述符是高并发网络服务编程的一种常见实现方式。Nebula 高性能通用网络框架即采用了UNIX域套接字传递文件描述符设计和实现。本文详细说明一下传送文件描述符的应用。 1. TCP服务...

Bwar
53分钟前
0
0
python操作Excle

# -*- coding: utf-8 -*-from openpyxl import load_workbook, Workbook#index:第几个sheet页,第一个sheet页的index为0def readExcle(filename,index): # 加载excle文件 wb = l......

淺陌离殇
55分钟前
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部