在(三)里用一個求Fibonacci數(shù)列的程序來說明CodeDOM是如何生成一些程序的基本語句的?,F(xiàn)在寫程序很少會直接寫幾個方法來讓Main()從頭調(diào)到尾的,總是要用幾個類來封裝封裝的。
在CodeDOM里一個類的字段、屬性、事件(講到事件,委托總是逃不了的)、方法等又是如何來生成的呢?上次只講到了類方法(CodeMemberMethod),在CodeTypeMember這個重量級的類下面還有很多沒有涉及,這次用一個比較完整的類來講余下的部分。
開始部分的幾下CodeCompileUnit、CodeNamespace、CodeNamespaceImport都是一樣的,就不多說了。
聲明一個名為DemoClass的類:
CodeTypeDeclaration MyClass = new CodeTypeDeclaration("DemoClass");
對一個Class來說除了名字外也沒什么好設(shè)置的,一般情況下這樣就行了。但有些定義了一些Attribute的要麻煩一點。要對MyClass的CustomAttributes屬性進行設(shè)置(不是MyClass的Attributes這個屬性,這個是設(shè)置可見性的)。
對于Attribute的生成CodeDOM有專門的類來實現(xiàn),就是CodeAttributeDeclaration。如要對DemoClass這個類加一個[Description("CodeDOM自動生成的一個類")]這樣的Attribute可以這樣寫:
MyClass.CustomAttributes.Add(new CodeAttributeDeclaration("Description",new CodeAttributeArgument(
new CodePrimitiveExpression("CodeDOM自動生成的一個類"))));
從上可以看到CodeAttributeDeclaration的構(gòu)造函數(shù),第一個參數(shù)是Attribute的名,第二個參數(shù)是Attribute的參數(shù)。對Description來說參數(shù)是“CodeDOM自動生成的一個類”這么一個字符串。當然不能直接用這個字符串來當構(gòu)造函數(shù)的參數(shù)。對于Attribute的參數(shù)又有一個專門的類的――CodeAttributeArgument,真是麻煩。還要把字符串包成一個CodeExpression去當CodeAttributeArgument的構(gòu)造函數(shù)的參數(shù)才算了結(jié)。(最后那個CodePrimitiveExpression在(三)里講到過了,它返回一個原始的表達式,實際上就是把括號里的東西類型轉(zhuǎn)換成一個CodeExpressoin)。
(上面的長長的一句就是在寫CodeDOM程序時構(gòu)造函數(shù)連用的寫法。當然你也可以不用這種new串聯(lián)的寫法,可以從最里層開始聲明一個個的變量一句句的構(gòu)造出來。上面一句就是分為四句了,不過這樣寫變量一多自己也要暈掉,所以一般不是太長的我還是喜歡連寫,如果把代碼格式編排一下一般寫10個new是沒什么問題的。比較頭痛的是在VS.NET中排好的格式到Word里會變掉)
好,一個類聲明好了,下面對類里的元素一個一個來說。
先是字段Field,從它的類層次結(jié)構(gòu)里能看出,這個肯定是用CodeMemberField來做的,如在類里聲明
private int myField;
可以這樣來寫:
CodeMemberField myField = new CodeMemberField("System.Int32","myField");
//myField.Attributes = MemberAttributes.Private;
MyClass.Members.Add(myField);
它的構(gòu)造函數(shù),前一個參數(shù)是類型,后一個參數(shù)是字段名。前一個參數(shù)有很多種寫法,這在(三)里說CodeParameterDeclarationExpression的時候提到過了(構(gòu)造函數(shù)有(Type,string)、(string,string)和(CodeTypeReference,string)這三種寫法),在CodeDOM里只要構(gòu)造函數(shù)有關(guān)于類型的一般都有上述的Type,string,CodeTypeReference三種寫法。
Attribute對于字段來說默認是private。所以這里可以注釋掉。
一般地上面幾點就夠了,如果字段聲明的同時要初始化的,只要設(shè)一下InitExpression就是了,這跟變量聲明不太一樣的地方是,它沒有相應(yīng)的構(gòu)造函數(shù),只能先new出來后,再設(shè)置相應(yīng)的InitExpression屬性。下面四句
CodeMemberField myArray = new CodeMemberField("System.Int32[]","myArray");
myArray.Attributes = MemberAttributes.Private;
myArray.InitExpression = new CodeArrayCreateExpression("System.Int32",10);
MyClass.Members.Add(myArray);
產(chǎn)生private int[] myArray = new int[10];
數(shù)組比較的特別一點,聲明的時候倒是容易,直接也在類型后加個“[]”就行了,就是初始化的時候麻煩一點,要用到數(shù)組創(chuàng)建表達式CodeArrayCreateExpression。它的用法參照一下對應(yīng)的產(chǎn)生代碼就明白了,構(gòu)造函數(shù)都是大同小異的。
字段聲明完,接著要寫構(gòu)造函數(shù)了。構(gòu)造函數(shù)就是一個比較特殊的類方法,CodeConstructor就是從CodeMemberMethod繼承下來聲明構(gòu)造函數(shù)用的。除了名字不太一樣,用法與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從上往下看,就是依次設(shè)置屬性名、類型、可見性,以及get和set方法的語句。這個GetStatements.Add()(或SetStatements.Add())里就隨你加了,簡單的屬性設(shè)置就如上面一樣,復雜的話就不斷地依續(xù)再往里Add就是了。
下面簡單的講一下Get和Set里一些細節(jié)的東西。首先是return this.myField;這個是如何來的,上次講Fibonacci數(shù)列時沒講到,返回值語句就是由CodeMethodReturnStatement產(chǎn)生的,要返回什么構(gòu)造函數(shù)里就放什么,很簡單。而this.myField就是類字段了,用CodeFieldReferenceExpression,不是上面的CodeMemberField,那個是聲明類字段用的,這里是要引用類字段(跟變量聲明與引用差不多)。同理CodePropertyReferenceExpression是就是用到類的屬性時用了。在屬性設(shè)置里“value”這個關(guān)鍵字會頻繁的出現(xiàn),在CodeDOM里對這個“value”也是有個專門的類的,就是CodePropertySetValueReferenceExpression了。比較特別的東西總是有個專門的類來表示,就象“this”就用CodeThisReferenceExpression來表示一樣。
在類的屬性里有個比較特殊的屬性就是索引器屬性,設(shè)置索引器屬性的寫法與設(shè)置一般的屬性基本一樣,只是把屬性名改為“Item”就行了。如:
public int this[int index] {。。。。。略}
這么一個索引器屬性由下述的語句產(chǎn)生:
CodeMemberProperty Pindex = new CodeMemberProperty();
Pindex.Comments.Add(new CodeCommentStatement("索引器屬性"));
Pindex.Type = new CodeTypeReference("System.Int32");
Pindex.Name = "Item";//屬性名設(shè)為Item時,CodeDOM就當作是索引器屬性處理
Pindex.Attributes = MemberAttributes.Public | MemberAttributes.Final;
Pindex.Parameters.Add(new CodeParameterDeclarationExpression("System.Int32","index"));
。。。。下略
類屬性的設(shè)置是夠麻煩的,但最麻煩的要數(shù)類事件了,如果只是聲明一下事件倒是簡單得很,但講到事件就不得不講委托,這一下篇幅就長了。這留下次講。