在(三)里用一个求Fibonacci数列的程序来说明CodeDOM是如何生成一些程序的基本语句的。现在写程序很少会直接写几个方法来让Main()从头调到尾的,总是要用几个类来封装封装的。
在CodeDOM里一个类的字段、属性、事件(讲到事件,委托总是逃不了的)、方法等又是如何来生成的呢?上次只讲到了类方法(CodeMemberMethod),在CodeTypeMember这个重量级的类下面还有很多没有涉及,这次用一个比较完整的类来讲余下的部分。
开始部分的几下CodeCompileUnit、CodeNamespace、CodeNamespaceImport都是一样的,就不多说了。
声明一个名为DemoClass的类:
CodeTypeDeclaration MyClass = new CodeTypeDeclaration("DemoClass");
对一个Class来说除了名字外也没什么好设置的,一般情况下这样就行了。但有些定义了一些Attribute的要麻烦一点。要对MyClass的CustomAttributes属性进行设置(不是MyClass的Attributes这个属性,这个是设置可见性的)。
对于Attribute的生成CodeDOM有专门的类来实现,就是CodeAttributeDeclaration。如要对DemoClass这个类加一个[Description("CodeDOM自动生成的一个类")]这样的Attribute可以这样写:
MyClass.CustomAttributes.Add(new CodeAttributeDeclaration("Description",new CodeAttributeArgument(
new CodePrimitiveExpression("CodeDOM自动生成的一个类"))));
从上可以看到CodeAttributeDeclaration的构造函数,第一个参数是Attribute的名,第二个参数是Attribute的参数。对Description来说参数是“CodeDOM自动生成的一个类”这么一个字符串。当然不能直接用这个字符串来当构造函数的参数。对于Attribute的参数又有一个专门的类的――CodeAttributeArgument,真是麻烦。还要把字符串包成一个CodeExpression去当CodeAttributeArgument的构造函数的参数才算了结。(最后那个CodePrimitiveExpression在(三)里讲到过了,它返回一个原始的表达式,实际上就是把括号里的东西类型转换成一个CodeExpressoin)。
(上面的长长的一句就是在写CodeDOM程序时构造函数连用的写法。当然你也可以不用这种new串联的写法,可以从最里层开始声明一个个的变量一句句的构造出来。上面一句就是分为四句了,不过这样写变量一多自己也要晕掉,所以一般不是太长的我还是喜欢连写,如果把代码格式编排一下一般写10个new是没什么问题的。比较头痛的是在VS.NET中排好的格式到Word里会变掉)
好,一个类声明好了,下面对类里的元素一个一个来说。
先是字段Field,从它的类层次结构里能看出,这个肯定是用CodeMemberField来做的,如在类里声明
private int myField;
可以这样来写:
CodeMemberField myField = new CodeMemberField("System.Int32","myField");
//myField.Attributes = MemberAttributes.Private;
MyClass.Members.Add(myField);
它的构造函数,前一个参数是类型,后一个参数是字段名。前一个参数有很多种写法,这在(三)里说CodeParameterDeclarationExpression的时候提到过了(构造函数有(Type,string)、(string,string)和(CodeTypeReference,string)这三种写法),在CodeDOM里只要构造函数有关于类型的一般都有上述的Type,string,CodeTypeReference三种写法。
Attribute对于字段来说默认是private。所以这里可以注释掉。
一般地上面几点就够了,如果字段声明的同时要初始化的,只要设一下InitExpression就是了,这跟变量声明不太一样的地方是,它没有相应的构造函数,只能先new出来后,再设置相应的InitExpression属性。下面四句
CodeMemberField myArray = new CodeMemberField("System.Int32[]","myArray");
myArray.Attributes = MemberAttributes.Private;
myArray.InitExpression = new CodeArrayCreateExpression("System.Int32",10);
MyClass.Members.Add(myArray);
产生private int[] myArray = new int[10];
数组比较的特别一点,声明的时候倒是容易,直接也在类型后加个“[]”就行了,就是初始化的时候麻烦一点,要用到数组创建表达式CodeArrayCreateExpression。它的用法参照一下对应的产生代码就明白了,构造函数都是大同小异的。
字段声明完,接着要写构造函数了。构造函数就是一个比较特殊的类方法,CodeConstructor就是从CodeMemberMethod继承下来声明构造函数用的。除了名字不太一样,用法与CodeMemberMethod及CodeEntryPointMethod差不多,这里就不详述了。
下面是属性的写法:
CodeMemberProperty MyProperty = new CodeMemberProperty();
MyProperty.Name = "MyProperty";
MyProperty.Type = new CodeTypeReference("System.Int32");
MyProperty.Attributes = MemberAttributes.Public | MemberAttributes.Final;
MyProperty.GetStatements.Add(new CodeMethodReturnStatement(new CodeFieldReferenceExpression(new CodeThisReferenceExpression(),"myField")));
MyProperty.SetStatements.Add(new CodeAssignStatement(new CodeFieldReferenceExpression(new CodeThisReferenceExpression(),"myField"),
new CodePropertySetValueReferenceExpression()));
MyClass.Members.Add(MyProperty);
这么长长的一段出来
public int MyProperty {
get {
return this.myField;
}
set {
this.myField = value;
}
}
这个CodeMemberProperty从上往下看,就是依次设置属性名、类型、可见性,以及get和set方法的语句。这个GetStatements.Add()(或SetStatements.Add())里就随你加了,简单的属性设置就如上面一样,复杂的话就不断地依续再往里Add就是了。
下面简单的讲一下Get和Set里一些细节的东西。首先是return this.myField;这个是如何来的,上次讲Fibonacci数列时没讲到,返回值语句就是由CodeMethodReturnStatement产生的,要返回什么构造函数里就放什么,很简单。而this.myField就是类字段了,用CodeFieldReferenceExpression,不是上面的CodeMemberField,那个是声明类字段用的,这里是要引用类字段(跟变量声明与引用差不多)。同理CodePropertyReferenceExpression是就是用到类的属性时用了。在属性设置里“value”这个关键字会频繁的出现,在CodeDOM里对这个“value”也是有个专门的类的,就是CodePropertySetValueReferenceExpression了。比较特别的东西总是有个专门的类来表示,就象“this”就用CodeThisReferenceExpression来表示一样。
在类的属性里有个比较特殊的属性就是索引器属性,设置索引器属性的写法与设置一般的属性基本一样,只是把属性名改为“Item”就行了。如:
public int this[int index] {。。。。。略}
这么一个索引器属性由下述的语句产生:
CodeMemberProperty Pindex = new CodeMemberProperty();
Pindex.Comments.Add(new CodeCommentStatement("索引器属性"));
Pindex.Type = new CodeTypeReference("System.Int32");
Pindex.Name = "Item";//属性名设为Item时,CodeDOM就当作是索引器属性处理
Pindex.Attributes = MemberAttributes.Public | MemberAttributes.Final;
Pindex.Parameters.Add(new CodeParameterDeclarationExpression("System.Int32","index"));
。。。。下略
类属性的设置是够麻烦的,但最麻烦的要数类事件了,如果只是声明一下事件倒是简单得很,但讲到事件就不得不讲委托,这一下篇幅就长了。这留下次讲。
联系客服