【前言】
一直想学习很多大师级人物,对于一个很小的事情,都能入木三分,来龙去脉的讲的头头是道。曾经为了搞清楚反射的概念,一直追述到Smith的博士论文(Smith, B. C. (1982): Reflection and Semantics in a Procedural Language, Ph.D. thesis, MIT Laboratory for Computer Science Report MIT-TR-272.)好不容易下载到原文,发现居然长达几百页。当时热情的火苗子刺溜吧唧,就灭了。
我想我本就不是大师,何必去装呢。干嘛非要把自己折磨成这样,此时终于明白“好读书不求甚解”的真正含义。生活工作,不都是为了开心吗。我想还是回归本性,用我喜欢的随意的风格,对于技术方面,工作中用不到的就跳过去,有偏见的地方也不怕人笑话,我把我看书的所思所想,好好说个痛快,这不是博客本来的初衷么。
1.1将源代码编译为托管模块。
“编译”就是“翻译”
说实在的,长期以来一直对“编译”这两个词抱着敬畏的态度。觉得编译技术高深莫测遥不可及。突然有天恍然大悟,“编译”就是“翻译”,编译就是把一种语言翻译成另一种语言,C#编译成IL,C++编译成汇编,"How are you"翻译成"你好吗",啥区别没有。什么是编译优化?就是把"How are you"翻译成"你吃了吗?"程序员是干什么的?不就是替人类充当与机器对话的翻译嘛!玩的都是文字游戏。如果程序员还有点社会价值的话,那纯粹是因为机器的价值。
CLR也是个翻译
CLR的名字没有JVM好听,关键是runtime这个单词给人一种空荡荡的感觉,而machine比较形象。其实JIT才是真正的翻译,把IL翻译成汇编语言。这让我想起我一个朝鲜族同学,她说,她学英语的时候,先要把英语在脑子里翻译成汉语,再把汉语翻译成韩语才能理解。这不就是C#->IL->汇编么。
IL的引入其实是为了解决COM的一些问题,比如一个名为Show的方法,COM里面包含的是Show方法的偏移地址,而.NET程序集里放的是Show方法签名。我坦白交代,以前没有做过COM的开发,所以开始的时候无法理解.NET里那么多互操作的东东。但是至少我现在知道了,office编程得用。一个函数动则几十个参数,还好C#4.0来救大家了。
“现在我们决定使用哪种编程语言”
由此谈到语言选择的问题,其实在现实工作中,使用什么语言我们根本做不了主,往往取决于毕业后第一家公司用什么语言。一旦选择了一种语言,基本就决定了以后大致的职业发展方向。如果是使用C语言做比较低层的开发,那么用到.NET平台的机会就少了。因此虽然.NET平台提供了多种语言选择的机会,但是有一个隐形的边界是我们可能会忽略的,那就是不管用什么语言开发,你都在使用.NET平台.
.NET平台主要是针对应用程序的,当我们选择了这个平台时,就意味着我们的工作会关注行业,关注领域,关注客户需求比较多。应用程序的特点是针对行业,变化多端,因人而变。在这个基础之上,我们在.NET平台上选择语言的唯一准则就是工作效率。这个工作效率并不光指语言的工作效率,同时包含团队成员的熟悉程度,语言普及程度等,都会影响效率。因此我们在开发过程中,或者使用开发语言和工具的过程中,尽量的忘记与此无关的东西,甚至忘记语言的名字,C#或者是JAVA,我们要的只是客户价值和工作效率。
IT技术和编程语言的百花齐放日新月异往往对程序员来说是个莫大的压力,如果是这样的话,应该是违背了语言发明者的初衷。总得来说,新的东西出来总是为了解决老东西解决不了的问题,因此对于新技术的关注点应该放在经常性的总结工作中碰到的疑难杂症,然后去新技术中寻找好的解决方案。如果你工作中真的啥问题没有,那么就恭喜你,可以不用管那些花开花落了。
我所在的公司在面向服务的新技术潮流上面就是一个很好的获益的例子。因为比较早的开展了Web Service的服务,现在已经有一个庞大的数据中心,行业内超过一半的信息都放在这里,我们的服务和软件是捆绑在一起销售的,服务费一年交一次。现在就算软件不卖钱,只卖服务费都够吃个七顿巴八顿的了,因此其他公司根本没法竞争,基本在这个行业站稳了老大的位置,这次金融风暴不仅没有倒下,反而收购了不少公司。
最后一个事情是最头疼的,就是对程序员的生涯规划问题。这么多新技术新语言,学哪个更有钱途呢?不知道,所以什么都得学。我觉得还是把现在公司里的技术彻底搞明白,然后寻找里面潜伏的问题,再从新技术中寻找解决方案比较踏实可靠。假如公司确实没有啥技术可言,那得考虑换家好点的公司了。
说点正事
一个程序集可以包含几个文件,我们通常看到的都是一个文件,我工作上也没用到过,不管它。
托管程序集也是DLL,com也是dll,win32也是dll.我一直很纳闷这三种东西有多少人十分清楚。首先,它们都是PE格式,再者,win32的dll是函数库,com的dl是类型库,而托管的dll嘛,就是加了IL和元数据的啦。不知道我说的对不对。
元数据又是一个不好听的名词。它可以说是IL类型的使用说明书,.NET本质论提到一点,它对于COM世界的改进来说,它是“机器可读”的。机器可读是CLR或者是虚拟机的前提呀。
1.2 将托管模块合并成程序集
源代码是原料,模块是零部件,DLL是汽车。
托管模块这破玩意一直困扰我很久,我们平常只看到一个类库在VS中编译完以后就生成DLL,好像跟模块并不是很熟的样子。结果是因为VS偷偷调用了MSBUILD。MSBUILD再调用SDK自带的编译器。如果把源代码看成原材料的话,把DLL看成汽车的话,讲源代码生成模块应该是把原材料变成零件的过程,结果VS太好心,直接把汽车就装好了。Assembly本来就有装配的意思。
资源文件也可以编译成模块,因此模块有两种,一种来自源代码,一种来自资源文件。你当然也可以把资源文件看成源代码, whatever.
foreach (Module var in Assembly.GetExecutingAssembly().GetModules()) {
string moduleName = var.Name;
}
上述代码遍历正在执行的程序集中所有模块,默认情况下只有一个模块,而且这个模块的名字跟生成的DLL或者EXE名字一样一样的,而且是带扩展名的。Type 类也有一个Module属性。
在实际工作中,我目前还没有碰到要单独处理Module的情况。倒是跟生成程序集有关的一大问题是每日构建的问题,Visual Build Pro和R2Build好像都不错,可以针对VS项目文件直接编译,不用任何配置。而且后者是免费的。既然有免费的,就可以不用研究MSBuild了。