【.net 深呼吸】细说CodeDom(1):结构大观

时间:2021-09-11 09:47:55

CodeDom 是啥东东?Html Dom听过吧,XML Dom听过吧。DOM一般可翻译为 文档对象模型,那 Code + DOM呢,自然是指代码文档模型了。如果你从来没接触过 CodeDom,你大概可以根据这个名字,推断它应该和代码文档模型有关。

这推断是靠谱的,CodeDom的功能,老周厚着脸皮把它归结为两大部分:

1、生成代码文档。这个听起来很玄?不玄,就是咱们在VS里常常耍的代码生成,比如你添加了一个服务引用,VS会帮你生成一个客户端代理类。

2、动态编译程序集。这个也好懂,就是动态编译。

 

很多朋友一遇到这个就怕,很难,很复杂。其实不然,CodeDom并不难,把思路理清了就好学了,这个事咱们暂时不谈,先说说老周要写的这系列文章吧,简单抛个砖,引个玉,免得大伙到时候向老周扔砖。

其实老周在几个世纪前曾在其他的博客上写过 CodeDom 相关的文章,大家也不要去人肉那些文章了,都是很肤浅很烂的文章,只是XX几笔就写完了,初学者朋友肯定看不懂的。没办法了,几个世纪前老周的编程水平比较烂,有时候翻开自己以前写的东西,都觉得很搞笑,自己当年怎么写这么SB的文章。

为了让更多朋友能够看懂,也为了向传统的编程教学方式发起挑战,有关CodeDom这系列文章,老周计划开启【废话模式】,老周会尽可能进行细致的讲解,到时候你不要觉得烦,废话会很多的。正因为废话多,所以一两篇文章肯定写不完的,至少得来个中篇小说的容量才行。

============================================

好,下面开始讲废话。

作为废话系列的第一篇,老周不会马上让你动手写代码的,既然是跟代码文档有关的东西,那就先复习一下代码的基础知识,很重要的,赶紧划重点,期末考试一定会考的。我的大学老师在上复习课的时候,老喜欢说这句话。记得当年老周就是不划重点,所以考了48.5分,然后被抓去补考,补考考了66分,形式上不用重修,于是就天下大吉了。上大学时,老周对考试从来都没认真过,包括考英语四级,作文里面还写上粗口,不知道阅卷老师看到之后会不会血压上升。

细细想一想,真不知道考试是为了什么,考60分又如何,考100分又如何,不还是一样吗。老周是出了名的上课不听课,复习不认真,考试不重视,哪怕面对高考也一样。但是老周绝不是不认真学习的人,只是跟贾宝玉差不多,怕看正经书,对于正经书以外的很多东西,老周反而很用功。

老周这个人,没什么优点,长得不帅(眼睛小,嘴巴扁,鼻子高),又不富(当年那张中信银行卡上时刻保持余额1.33元),1米78的身材也不高。唯一的优点就是兴趣广,爱好多,杂学旁收,从不客气,只要别让我读教材做考试题就行。

所以当年有妹子就写了一首诗来形容老周:

不爱烟酒不羡富,苦学逸少子昂书。

酷喜上课看杂志,最怕临考背试题。

偶得仙乐歌一阙,沉思漫笔有洞天。

 

CodeDom支持如C#、VB、C++、JScript这几种语言的代码生成,当然,必须是生成CLR能认识的代码,所以这里头的C++主要是托管C++。

现在,你开始回忆一下,满怀深情地回忆一下,一个CLR程序集里面有什么?由于在VS里面,一个项目就是一个程序集,或者你可以想一下,一个项目的代码里面有啥。

咱们从外向里一层一层的刷一下。

A、一个项目中是不是有N个命名空间?想起来了吧,而命名空间里面可以包括命名空间,不过,CodeDom中不使用嵌套命名空间,比如,System和System.IO可以认为是两个单独的命名空间。

B、然后,大伙再想想,一个命名空间下有啥。类型,好,类型又有多少种?数一数,类、结构、枚举、接口、委托。

C、类型下面有什么?对,成员,那么类型成员有几种。再数一数,构造函数、字段、属性、方法、事件。

     1)如果类型是泛型类型,还会包含若干泛型列表,泛型参数可能还带有约束。

     2)如果成员是方法,会包含有输入参数、输出参数或返回值;对于属性成员,会有get和set访问器。对于索引器,会有索引变量。

D、类型成员下包含语句集合(Statement),通常翻译为语句比较好听。常规代码语句以英文的分号(;)结束,这个大家都很熟悉了,当然,像if、while、for这些语句比较特别,它们往往包含多个条件。

E、语句是由表达式和运算符(操作符)组成。

比如,这样就是一个表达式,常量表达式。

300

这样就是一个语句,赋值语句。

k = 300;

这是语句,它包括一个 = 运算符(赋值运算符),一个变量引用表达式(k),以及一个常量表达式(300)。

 

有一个语句大家要注意,就是这样:

double x = 0.0021d;

别看它很简单,别看它是很基础的知识,这里面的门道你还真未必已经掌握。

它是一个复合语句,其实它包含两个语句:声明语句(double x;),赋值语句(x = 0.0021d)。如果拆开来,可以这样写。

double x;
x
= 0.0021d;

而 double x = 0.0021d 是在变量声明时顺便进行初始化。在两种写法在 CodeDom 代码生成中是应当区别,这个后续的文章中老周会讲的,现在你暂时了解一下。

 

好,代码的结构大观我们复习完了,老周保证你期末考试能考95分。

既然是要讲CodeDom的,就得把代码结构中的各个对象与CodeDOM类型对号入座,这样可以方便大家熟悉CodeDom模型。

来,先喝杯牛奶,做好准备,下面开始接触 CodeDom了。

 

=========================================

CodeDom 的根容器是 CodeCompileUnit,它是一个编译单元,这个类你必须认识,不然以后就无法CodeDom了,如果要进行动态编译,就应该用一个编译单元来编译,不能用一句代码来编译,因为这样生成的程序没有实际意义,也不能运行。

编译单元你可以把它类比一个VS项目,一个程序集。所以,你会看到,CodeCompileUnit 类有一个 Namespaces 属性,这使得一个编译单元可以包含 N 个命名空间。

一个命名空间可以用 CodeNamespace 类来表示,Comments 用来设置给命名空间写的注释,Imports就是这个命名空间中要引入的其他命名空间,就是C#中的 using,VB中的 Import,托管C++中的 using。

一个 CodeNamespace 类公开了 Types 属性,表示某个命名空间下的类型集合。要声明一个类型,使用 CodeTypeDeclaration 类,至于定义的是类,是接口,还是枚举,可以用类的属性来决定。例如IsInterface指定是否为接口,IsClass指定是否为类,IsEnum指定是否为枚举等。如果类是从其他类型派生的,或者实现接口,那可以向BaseTypes属性添加基类型。如果基类是Object,可以忽略。

但是,委托类型的声明比较特殊,它使用 CodeTypeDelegate 类。

一个类型之下包含的是类型成员,它们对应的CodeDom类有:CodeMemberField(字段)、CodeMemberProperty(属性)、CodeMemberMethod(方法)、CodeMemberEvent(事件)。

注意,表示类型构造函数有两个类。如果是静态构造函数,因为它是属于类型而非实例,所以要用 CodeTypeConstructor;对于普通面向实例的构造函数要使用 CodeConstructor。

 

好了,今天就讲到这里吧,讲多了,大伙会接受不了。下一篇文章,老周再介绍代码表达式和代码语句。