【.net 深呼吸】細說CodeDom(8):分支與循環

有人會問,爲啥 CodeDom 不會生成 switch 語句,爲啥沒生成 while 語句之類。要注意,CodeDom只關心代碼邏輯,而不是語法,語法是給寫代碼的人用的。若是用.net的「反編譯」工具的朋友會知道,你用while語句寫了一段代碼,而後編譯生成程序集,再用工具把代碼「反」出來,此時你會發現,你原來寫的是while語句,但出來的是for語句,道理是同樣的,「反編譯」工具只關心代碼的執行邏輯,而不是語法。因此,你天然沒法用 CodeDom 來生成var關鍵字來聲明變量,也沒法生成用 Lambda 表達式表示的方法,也不能生成僅有get和set的屬性定義語法。ide

所以,你們不要把語法和邏輯搞混。工具

 

先來介紹一下分支,分支語句相似 if 語句,由 CodeConditionStatement 類表示,它須要三個要素:spa

一、條件,用於判斷給定的表達式是否爲true。.net

二、當條件成立時所執行的代碼。3d

三、當條件不成立時所執行的代碼。code

 

下面舉個例子,讓某數除以2,並取模(即取餘),若是結果爲0,即爲偶數,不然爲奇數。代碼以下。blog

            // 取模運算
            CodeBinaryOperatorExpression modexp = new CodeBinaryOperatorExpression();
            modexp.Operator = CodeBinaryOperatorType.Modulus;
            modexp.Left = new CodePrimitiveExpression(6);
            modexp.Right = new CodePrimitiveExpression(2);
            // 相等運算
            CodeBinaryOperatorExpression eqexp = new CodeBinaryOperatorExpression();
            eqexp.Operator = CodeBinaryOperatorType.IdentityEquality;
            eqexp.Left = modexp;
            eqexp.Right = new CodePrimitiveExpression(0);
            // 分支語句
            CodeConditionStatement codst = new CodeConditionStatement();
            // 設置判斷條件
            codst.Condition = eqexp;
            // 若是爲真
            codst.TrueStatements.Add(new CodeMethodInvokeExpression(new CodeMethodReferenceExpression(new CodeTypeReferenceExpression(typeof(Console)), nameof(Console.WriteLine)), new CodePrimitiveExpression("這是偶數。")));
            // 若是爲假
            codst.FalseStatements.Add(new CodeMethodInvokeExpression(new CodeMethodReferenceExpression(new CodeTypeReferenceExpression(typeof(Console)), nameof(Console.WriteLine)), new CodePrimitiveExpression("這是奇數。")));

            CodeDomProvider provider = CodeDomProvider.CreateProvider("cs");
            provider.GenerateCodeFromStatement(codst, Console.Out, null);

生成的代碼以下:ip

 

有時候,代碼只須要判斷條件成立並進行處理,而忽略條件不成立的情形,這時候 FalseStatements 中能夠不添加任何語句。以下面例子。rem

            // 定義變量
            CodeVariableDeclarationStatement varst = new CodeVariableDeclarationStatement(typeof(string), "str", new CodePrimitiveExpression("i-s-h-e-j-d-u"));
            // 訪問變量實例的屬性
            CodePropertyReferenceExpression prpref = new CodePropertyReferenceExpression(new CodeVariableReferenceExpression(varst.Name), nameof(string.Length));
            // 生成判斷條件的表達式
            CodeBinaryOperatorExpression codexp = new CodeBinaryOperatorExpression();
            codexp.Operator = CodeBinaryOperatorType.GreaterThan;
            codexp.Left = prpref;
            codexp.Right = new CodePrimitiveExpression(5);
            // 分支語句
            CodeConditionStatement codstatement = new CodeConditionStatement();
            codstatement.Condition = codexp;
            // 條件成立時
            CodeMethodInvokeExpression invmeth = new CodeMethodInvokeExpression();
            invmeth.Method = new CodeMethodReferenceExpression(new CodeTypeReferenceExpression(typeof(Console)), nameof(Console.WriteLine));
            invmeth.Parameters.Add(new CodePrimitiveExpression("字符串長度超出範圍。"));
            codstatement.TrueStatements.Add(invmeth);

            CodeDomProvider prd = CodeDomProvider.CreateProvider("cs");
            prd.GenerateCodeFromStatement(varst, Console.Out, null);
            prd.GenerateCodeFromStatement(codstatement, Console.Out, null);

這個例子生成代碼爲:聲明一個字符串類型變量,並初始化。而後判斷其長度,並按條件執行輸出。生成的代碼以下。字符串

 

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

循環語句的生成也不難,它由 CodeIterationStatement 類負責生成,其結構相似於 for 語句,由個要素組成:

一、循環條件的初始值。

二、判斷是否執行循環的條件。

三、對循環條件的更改。

 

下面經過示例,生成一個標準的for循環。

            CodeIterationStatement its = new CodeIterationStatement();
            // 初始化條件
            its.InitStatement = new CodeVariableDeclarationStatement(typeof(int), "i", new CodePrimitiveExpression(0));
            // 條件檢查
            its.TestExpression = new CodeBinaryOperatorExpression(new CodeVariableReferenceExpression("i"), CodeBinaryOperatorType.LessThan, new CodePrimitiveExpression(9));
            // 每一輪循環後對條件的更改
            its.IncrementStatement = new CodeAssignStatement(new CodeVariableReferenceExpression("i"), new CodeBinaryOperatorExpression(new CodeVariableReferenceExpression("i"), CodeBinaryOperatorType.Add, new CodePrimitiveExpression(2)));
            // 循環體
            its.Statements.Add(new CodeCommentStatement("循環體代碼"));

            CodeDomProvider prd = CodeDomProvider.CreateProvider("vb");
            prd.GenerateCodeFromStatement(its, Console.Out, null);

初始化一個變量i,條件是它小於9時發生循環,每次循環後會把條件加上2。

這時候會發現,生成的 VB 代碼是While循環。

而生成的C#代碼則是for循環。

 

你甭管它是什麼語法格式,只要邏輯上對了就行,這是生成代碼,不是寫代碼,不要患有強迫症。

 

想不想來個死循環,其實,死循環只要讓 TestExpression 永遠爲true,而且, IncrementStatement 不會更改條件的值就好了。好比這樣。

            CodeIterationStatement itsmt = new CodeIterationStatement();
            itsmt.InitStatement = new CodeVariableDeclarationStatement(typeof(bool), "n", new CodePrimitiveExpression(true));
            itsmt.TestExpression = new CodeVariableReferenceExpression("n");
            itsmt.IncrementStatement = new CodeAssignStatement(new CodeVariableReferenceExpression("n"), new CodePrimitiveExpression(true));
            itsmt.Statements.Add(new CodeCommentStatement("無限做死……"));

            CodeDomProvider prd = CodeDomProvider.CreateProvider("cs");
            prd.GenerateCodeFromStatement(itsmt, Console.Out, null);

初始化變量爲true,並每一輪循環後都讓它爲true。生成代碼以下:

 

其實,還能夠更簡單一點。

            CodeIterationStatement itsmt = new CodeIterationStatement();
            itsmt.InitStatement = new CodeSnippetStatement("");
            itsmt.TestExpression = new CodePrimitiveExpression(true);
            itsmt.IncrementStatement = new CodeSnippetStatement("");
            itsmt.Statements.Add(new CodeCommentStatement("無限做死……"));

            CodeDomProvider prd = CodeDomProvider.CreateProvider("cs");
            prd.GenerateCodeFromStatement(itsmt, Console.Out, null);

老周在前面介紹過,CodeSnippetStatement 類能夠用原義文本生成代碼,這裏咱們把原義文本用空字符表示,就會生成空白語句。

 

因此,生成的C#代碼是這樣的:

 

生成的 VB 代碼是這樣的:

 

生成的C++代碼是這樣的:

 

 好了,有關分支和循環的邏輯代碼的生成就介紹到此了,下一篇文章,我們就開始說說編譯代碼的事。

相關文章
相關標籤/搜索