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