【.net 深呼吸】细说CodeDom(8):分支与循环

有人会问,为啥 CodeDom 不会生成 switch 语句,为啥没生成 while 语句之类。要注意,CodeDom只关心代码逻辑,而不是语法,语法是给写代码的人用的。如果用.net的“反编译”工具的朋友会知道,你用while语句写了一段代码,然后编译生成程序集,再用工具把代码“反”出来,此时你会发现,你原来写的是while语句,但出来的是for语句,道理是一样的,“反编译”工具只关心代码的执行逻辑,而不是语法。所以,你自然无法用 CodeDom 来生成var关键字来声明变量,也无法生成用 Lambda 表达式表示的方法,也不能生成仅有get和set的属性定义语法。

因此,大家不要把语法和逻辑搞混。

先来介绍一下分支,分支语句类似 if 语句,由 CodeConditionStatement 类表示,它需要三个要素:

1、条件,用于判断给定的表达式是否为true。

2、当条件成立时所执行的代码。

3、当条件不成立时所执行的代码。

下面举个例子,让某数除以2,并取模(即取余),如果结果为0,即为偶数,否则为奇数。代码如下。

            // 取模运算
            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);

生成的代码如下:

有时候,代码只需要判断条件成立并进行处理,而忽略条件不成立的情形,这时候 FalseStatements 中可以不添加任何语句。如下面例子。

            // 定义变量
            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 语句,由个要素组成:

1、循环条件的初始值。

2、判断是否执行循环的条件。

3、对循环条件的更改。

下面通过示例,生成一个标准的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++代码是这样的:

好了,有关分支和循环的逻辑代码的生成就介绍到此了,下一篇文章,咱们就开始说说编译代码的事。

时间: 2024-08-06 03:39:30

【.net 深呼吸】细说CodeDom(8):分支与循环的相关文章

java分支与循环

一.基础数据类型(四类八种):不能为null整数型byte----2的8次方short----2的16次方int----2的32次方long----2的64次方浮点型float----4个double---8个字节布尔型boolean(true, false)字符型char(可以是一个字母, 也可以是一个汉字) int a = 5;全部存到栈引用类型:String s = "abc";所有的类所有的数组所有的接口 二.分支if(表达式_布尔值) {...} if(表达式_布尔值) {.

PHP 分支与循环

一.概述: 上面一章我们讲解了PHP当中的运算符和表达式,通过上面的知识点我们就可以完成一些基本的运算操作了.但是涉及到一些比较复杂的逻辑,分支与循环就必不可少了.通过分支和循环的结合使用可以使业务更加复杂,代码功能更加强大. 二. 常见的分支结构 if语句 1 单个 if 语句 基本格式: if(条件表达式){ 语句组; //语句组为单条语句时可省略"{ }". } 当条件表达式的值为真(true)时,PHP将执行语句组,相反条件表达式的值为假(false)时,PHP将不执行语句组,

PHP 分支与循环和goto

分支与循环 1.if中的判断条件is_bool():判断是否是布尔型is_int().is_integer()和is_long():判断是否为整型.is_float().is_double()和is_real():判断是否为浮点型is_string():判断是否为字符串is_array():判断是否为数组is_object():判断是否为对象is_resource():判断是否为资源类型is_null():判断是否为nullis_scalar():判断是否为标量is_numeric():判断是否

汇编学习-分支与循环

在高级语言程序设计中,我们不仅要求程序可以顺序运行,还要求其可以运行不同分支,或者反复运行某些操作.在汇编语言中,相同具有相同的能力,可以由对应的指令来控制程序的运行流程.由于毕竟高级语言都是汇编实现的,仅仅是不直观而已. 转移 无条件转移为JMP.类似c语言中的 goto. 在c语言中,goto是不推荐使用的,会使程序难以控制和理解,但在汇编中,没有对应的if 和 while语句.仅仅能使用 JMP来完毕逻辑复杂的控制结构. JMP分为段内转移和段间转移.只是在windows编程上,一个代码段

MSIL 教程(二):数组、分支、循环、使用不安全代码和如何调用Win32 API(转)

转自:http://www.cnblogs.com/Yahong111/archive/2007/08/16/857574.html 续上文[翻译]MSIL 教程(一) ,本文继续讲解数组.分支.循环.使用不安全代码和如何调用Win32 API 数组 本程序分配一个int型的数组并给他的元素赋值,然后打印出元素和数组的长度. 命令: newarr type— 生成一个元素类型为type 的数组.数组的大小必须在调用该命令前装入堆栈.该命令会把一个数组的引用装入堆栈. stelem.i4— 给一个

SQL连接查询、变量、运算符、分支、循环语句

连接查询:通过连接运算符可以实现多个表查询.连接是关系数据库模型的主要特点,也是它区别于其它类型数据库管理系统的一个标志. 常用的两个链接运算符: 1.join   on 2.union 在关系数据库管理系统中,表建立时各数据之间的关系不必确定,常把一个实体的所有信息存放在一个表中.当检索数据时,通过连接操作查询出存放在多个表中的不同实体的信息.连接操作给用户带来很大的灵活性,他们可以在任何时候增加新的数据类型.为不同实体创建新的表,随后通过连接进行查询. 示例一: 示例二: 示例三: 示例四:

Python学习杂记_4_分支和循环

分支 和 循环 分支和循环这俩结构在各语言中都有着很重要的地位,当然我之前都没有学好,这里总结一下在Python学习中对这俩结构的认识. 分支结构 # 单分支 if 条件判断: 执行语句- # 双分支 if 条件判断: 执行语句- else: 执行语句- #多分支 if 条件判断: 执行语句- elif: 执行语句- else: 执行语句- 循环结构 1. while循环 ,需要定义循环变量来控制循环. i = 0初始化一个控制循环的变量 while 有关循环变量的条件判断: 执行循环语句 -

java里的分支语句--程序运行流程的分类(顺序结构,分支结构,循环结构)

JAVA里面的程序运行流程分三大类: 1,顺序结构:顺序结构就是依次执行每一行代码 2,分支结构:分支结构就是按不同的条件进行分支 3,循环结构:一段代码依条件进行循环执行. 其中,分支结构有两大类: if...else...结构和switch...结构       switch中的case支持的数据类型只有四种:    char  (字符型)    byte  (比特型)    short (短整型)    int     (整型) 注意switch里面的判断语句后面需要加break,否则的话

Android.mk (2) 函数进阶教程 - 分支、循环、子程序

https://www.jianshu.com/p/674dc7d7b4b0 函数进阶教程 - 分支.循环.子程序 按照面向过程程序设计的标准流程,我们讲完了顺序结构,就要讲分支.循环和子程序.下面我们就开始讲用于分支.循环和子程序调用功能的函数. 分支函数 要走分支,一定是要有条件要判断. 在Makefile里,最主要的判断就是看字符串能不能找到了. 通过findstring函数来进行这个判断,然后用if函数使用findstring函数的结果. 例: .PHONY : all5 bootoat