【.net 深呼吸】細說CodeDom(2):運算式、語句

來源:互聯網
上載者:User

標籤:擷取   field   setvalue   自動   arp   unit   看到了   .com   binary   

在上一篇文章中,老周厚著臉皮給大夥介紹了代碼文檔的基本結構,以及一些代碼對象與CodeDom類型的對應關係。

在評論中老周看到有朋友提到了 Emit,那老周就順便提一下。嚴格上說,Emit並不是針對代碼文檔產生和編譯而設計的,Emit一方面可以即時發出 IL 指令,另一方面也支援動態程式集,即可以在運行時建立程式集,並可以定義類型,然後可以執行。而CodeDom所針對的是代碼文檔的產生和編譯,所以說,是有所不同的。

哦,是了,還有一個玩意兒挺有趣,也提一下吧——動態 Linq 運算式樹狀架構。它也跟動態編譯有點像,就是動態建立 LINQ運算式樹狀架構,LINQ懂吧,別告訴你不知道,這是玩.net的必備法寶,運算式樹狀架構建立後會Just-In-Time 編譯為一個委託執行個體,使用時直接調用產生的委託執行個體即可。

好,下面開始本文的內容。先說說運算式,因為語句是由運算式組成的,按照正常人類的思考方式,應當由小及大來學習。啥是運算式呢,其實可以說,運算式是代碼文檔的基礎元素,比如一個int值 2500,就是一個運算式;字串常量用雙引號包起來,如"abc",也是一個運算式;當前類執行個體的引用 this也是運算式;基類執行個體的引用 base,也是運算式;變數名 a 也是運算式;數組索引,如 [0] 也是運算式;方法中的輸出參數 out 也是運算式……

CodeExpression 是所有運算式對象的公用基類,從它的衍生類別來看,咱們不妨對錶達式的類型先來個非專業總結,這樣有助於大家掌握思路。這個類的衍生類別相當多,不要暈,思路理清了,就不怕它數量多。

老周大致把這些運算式類劃分以下幾類(僅供參考):

1、建立執行個體。如CodeArrayCreateExpression、CodeDelegateCreateExpression等,大家可以根據它們的名字來猜猜其作用,現在你不必弄明白到底怎麼用,後面老周會教你怎麼用的。

2、引用。比如當前執行個體引用(this)CodeThisReferenceExpression,再比如引用某個執行個體的方法的語句 CodeMethodReferenceExpression, 像 x.Run(……)。再比如屬性裡面set訪問器中,大家都知道有一個 value 關鍵字,要引用它可以用 CodePropertySetValueReferenceExpression 類。

3、運算子(操作符)。這好懂了吧,+-*/=()==!<>這些都是操作符。對於二進位運算,可以用CodeBinaryOperatorExpression,它通過 CodeBinaryOperatorType 枚舉來規範要用到的運算子,如加法、減法等。如果要進行類型轉換,可以使用類型轉換運算子 CodeCastExpression,它也是一種運算式。如果想用 typeof 運算子,可以使用 CodeTypeOfExpression 類。

4、其他。比較零碎。像參數引用,數組索引等。

 

很多運算式類在使用時,直接賦相應的值就行,用習慣了之後也不會很難。在舉例之前,老周先講一下如何產生代碼,相信大夥在做完例子後,最迫切的就是想看看產生的程式碼是啥樣子的。

產生代碼要用 CodeDomProvider 類(位於System.CodeDom.Compiler命名空間下),這個類不用 new 的,它有一個靜態 CreateProvider 方法,調用後直接返回 CodeDomProvider 執行個體,調用方法時,可以用一個字元來指定程式設計語言。比如,C#、cs、CSharp都可以表示C#語言;用 VB、VisualBasic都表示VB語言;用js、JScript表示jscript語言;用cpp表示C++語言(託管)。名字是不區分大小寫,所以,CS和cs都一樣。

然後,你會看到這個類有一堆GenerateCodeFromXXXX的方法,這些XXXX可以是運算式、語句、編譯單元、類型定義等。產生代碼時,你必須提供一個 TextWriter,代碼產生後會寫進這個writer裡面。

下面給大家示範一下,咱們就把代碼輸出到控制台吧,這樣馬上就能看到效果。

假設我定義一個類型,名叫 Dog,它是結構。來,看代碼:

            CodeTypeDeclaration dcl = new CodeTypeDeclaration("Dog");            dcl.IsStruct = true;            dcl.Attributes = MemberAttributes.Public;

IsStruct 指明它是個結構,CodeTypeDeclaration類建構函式中傳的是類型的名字,叫Dog。Attributes屬性設定這個類型為公用類型(public)。

好,現在我們就定義好一個類型了,下面咱們來產生C#、VB和C++三種語言的代碼。

            // 產生C#代碼            CodeDomProvider provider = CodeDomProvider.CreateProvider("cs");            Console.WriteLine("產生 C# 代碼:");            provider.GenerateCodeFromType(dcl, Console.Out, null);            // 產生 VB 代碼            provider = CodeDomProvider.CreateProvider("vb");            Console.WriteLine("\n產生 VB 代碼:");            provider.GenerateCodeFromType(dcl, Console.Out, null);            // 產生 C++ 代碼            provider = CodeDomProvider.CreateProvider("cpp");            Console.WriteLine("\n產生 C++ 代碼:");            provider.GenerateCodeFromType(dcl, Console.Out, null);

運行後,就會看到以下內容。

 

方法很簡單,先用CreateProvider靜態方法擷取特定語言的提供者,然後 GenerateCodeFromXXXXX,你要從什麼代碼對象產生,就調用哪個版本,比如要從編譯單元產生代碼,就應當調用GenerateCodeFromCompileUnit方法,要從定義的命名空間產生代碼就調用GenerateCodeFromNamespace方法。

 

好,咱們開始練習,先來個操作符的,下面例子用來產生 a + b,a和b是變數名,我們先不管變數是哪來的,反正目的是使用操作符。

            CodeVariableReferenceExpression left = new CodeVariableReferenceExpression("a");            CodeVariableReferenceExpression right = new CodeVariableReferenceExpression("b");            CodeBinaryOperatorExpression opt = new CodeBinaryOperatorExpression();            opt.Operator = CodeBinaryOperatorType.Add;            opt.Left = left;            opt.Right = right;

一個操作符運算式,通常會三個組成元素——運算子,左邊運算元,右邊運算元。在這個例子裡面,左邊和右邊分別使用變數引用,即用到 CodeVariableReferenceExpression 類,這個類用法也簡單,只要提供一個變數名稱就行了。

最後產生代碼為:

(a + b)

 

再看一個例子。

            CodeThisReferenceExpression thisexpr = new CodeThisReferenceExpression();            CodeFieldReferenceExpression fexp = new CodeFieldReferenceExpression();            fexp.FieldName = "m_val";            fexp.TargetObject = thisexpr;            CodeBinaryOperatorExpression opt = new CodeBinaryOperatorExpression();            opt.Left = fexp;            opt.Right = new CodePrimitiveExpression((int)300);            opt.Operator = CodeBinaryOperatorType.Assign;

上面例子中的 CodeBinaryOperatorExpression 對象指定運算子為 Assign, 即賦值符號(=)。然後我們再看它兩邊的運算元。左邊引用的是當前執行個體的欄位,首先要建立一個CodeThisReferenceExpression,這個類不需要指定任何參數,因為它產生的就是this關鍵字,然後用CodeFieldReferenceExpression來引用this執行個體中一個叫m_val的欄位;右邊運算元是一個常量,常量值可以用CodePrimitiveExpression來表示。

CodePrimitiveExpression 一般用於指定基礎類型的常量值,如int、string、double等。如這樣

CodePrimitiveExpression p = new CodePrimitiveExpression(0.1322d);

產生代碼後,會自動將傳入的值表示為double類型常量。產生代碼如下:

0.1322D

再比如

  CodePrimitiveExpression p = new CodePrimitiveExpression("ask");

就會產生字串常量:

"ask"

好了,上面的賦值運算式最終得到的結果如下:

(this.m_val = 300)

 

下面咱們來產生一句 typeof運算式。

            CodeTypeOfExpression texp = new CodeTypeOfExpression(typeof(string));            Console.WriteLine("C# 代碼:");            CodeDomProvider prd = CodeDomProvider.CreateProvider("cs");            prd.GenerateCodeFromExpression(texp, Console.Out, null);            Console.WriteLine("\n");            Console.WriteLine("VB 代碼:");            CodeDomProvider prd2 = CodeDomProvider.CreateProvider("vb");            prd2.GenerateCodeFromExpression(texp, Console.Out, null);

很簡單,執行個體化 CodeTypeOfExpression 時,把某個類型的type傳進去就行了。

最後輸出的代碼如下:

C# 代碼:typeof(string)VB 代碼:GetType(String)

 

咱們再來個類型轉換的運算式。

            CodeVariableReferenceExpression vexp = new CodeVariableReferenceExpression();            vexp.VariableName = "x";            CodeTypeReference tref = new CodeTypeReference(typeof(decimal));            CodeCastExpression cexp = new CodeCastExpression();            cexp.Expression = vexp;            cexp.TargetType = tref;

CodeVariableReferenceExpression主要設定兩個參數,Expression 指的是要進行類型轉換的對象,通常是一個變數;TargetType是要轉換的目標類型,需要用一個CodeTypeReference來封裝,使用時直接把類型的type傳遞即可。

類型轉換運算式產生代碼如下:

((decimal)(x))

 

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

學會使用運算式後,語句就好辦了,因為語句就是由運算式組成的,只是為了說明是語句,在C類風格的語言中會以英文的分號結尾(VB除外)。

來,來一句指派陳述式。

            CodeVariableReferenceExpression left = new CodeVariableReferenceExpression("f");            CodePrimitiveExpression sexp = new CodePrimitiveExpression("so hot");            CodeAssignStatement assstm = new CodeAssignStatement();            assstm.Left = left;            assstm.Right = sexp;

CodeAssignStatement 和剛才的賦值運算式很像,也需要指定左邊的運算式和右邊的運算式。最後產生的程式碼如下:

f = "so hot";

大家看到了,語句結尾是有分號的,剛才的運算式是沒有分號的。

 

接下來,咱們聲明一個變數,然後給它一個值。

            CodeVariableDeclarationStatement decl = new CodeVariableDeclarationStatement(typeof(int), "n");            CodeAssignStatement ass = new CodeAssignStatement();            ass.Left = new CodeVariableReferenceExpression("n");            ass.Right = new CodePrimitiveExpression(98000);            CodeDomProvider prd = CodeDomProvider.CreateProvider("cs");            prd.GenerateCodeFromStatement(decl, Console.Out, null);            prd.GenerateCodeFromStatement(ass, Console.Out, null);

這段實際上是產生了兩句代碼,第一句是聲明語句,CodeVariableDeclarationStatement將產生聲明變數的語句,需要指定變數的類型和變數名。

第二句是指派陳述式,需要指定左邊和右邊。左邊引用變數n,右邊是常量值。

產生代碼如下:

int n;n = 98000;

以上代碼不夠簡潔,我們完全可以在聲明變數的時候,就將它初始化,這樣只用一個語句就可以了。

CodeVariableDeclarationStatement decl = new CodeVariableDeclarationStatement(typeof(int), "n", new CodePrimitiveExpression(98000));

這樣一個語句就完成了,產生的程式碼如下:

int n = 98000;

 

這裡老周不會將所有語句一個個做介紹。本文介紹的這些運算式和語句,主要是協助初學者朋友們練手,以便找到感覺,剩下的一些複雜的語句——如選擇語句、迴圈語句這些,老周在後面的文章中會介紹的。

OK,今天的牛皮就吹到這裡,希望對各位有協助。

 

【.net 深呼吸】細說CodeDom(2):運算式、語句

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.