有人会问,为啥 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();
modexp.Right = new CodePrimitiveExpression();
// 相等运算
CodeBinaryOperatorExpression eqexp = new CodeBinaryOperatorExpression();
eqexp.Operator = CodeBinaryOperatorType.IdentityEquality;
eqexp.Left = modexp;
eqexp.Right = new CodePrimitiveExpression();
// 分支语句
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();
// 分支语句
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());
// 条件检查
its.TestExpression = new CodeBinaryOperatorExpression(new CodeVariableReferenceExpression("i"), CodeBinaryOperatorType.LessThan, new CodePrimitiveExpression());
// 每一轮循环后对条件的更改
its.IncrementStatement = new CodeAssignStatement(new CodeVariableReferenceExpression("i"), new CodeBinaryOperatorExpression(new CodeVariableReferenceExpression("i"), CodeBinaryOperatorType.Add, new CodePrimitiveExpression()));
// 循环体
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++代码是这样的:

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

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

  1. SQL变量、运算符、分支、循环语句

    变量: SQL语言也跟其他编程语言一样,拥有变量.分支.循环等控制语句. 在SQL语言里面把变量分为局部变量和全局变量,全局变量又称系统变量. 局部变量: 使用declare关键字给变量声明,语法非常 ...

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

    连接查询:通过连接运算符可以实现多个表查询.连接是关系数据库模型的主要特点,也是它区别于其它类型数据库管理系统的一个标志. 常用的两个链接运算符: 1.join   on 2.union 在关系数据库 ...

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

    JAVA里面的程序运行流程分三大类: 1,顺序结构:顺序结构就是依次执行每一行代码 2,分支结构:分支结构就是按不同的条件进行分支 3,循环结构:一段代码依条件进行循环执行. 其中,分支结构有两大类: ...

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

    转自:http://www.cnblogs.com/Yahong111/archive/2007/08/16/857574.html 续上文[翻译]MSIL 教程(一) ,本文继续讲解数组.分支.循环 ...

  5. 了不起的分支和循环03 - 零基础入门学习Python009

    了不起的分支和循环03 让编程改变世界 Change the world by program while循环 说完了分支我们来说说循环,标准的while循环语法我们已经可以熟悉掌握了. 这里我们就简 ...

  6. 了不起的分支和循环02 - 零基础入门学习Python008

    了不起的分支和循环02 让编程改变世界 Change the world by program 上节课,小甲鱼教大家如何正确的打飞机,其要点就是:判断和循环,判断就是该是不该做某事,循环就是持续做某事 ...

  7. 了不起的分支和循环01 - 零基础入门学习Python007

    了不起的分支和循环01 让编程改变世界 Change the world by program 我们今天的主题是"了不起的分支和循环",为什么小甲鱼不说C语言,不说Python了不 ...

  8. PHP 分支与循环

    一.概述: 上面一章我们讲解了PHP当中的运算符和表达式,通过上面的知识点我们就可以完成一些基本的运算操作了.但是涉及到一些比较复杂的逻辑,分支与循环就必不可少了.通过分支和循环的结合使用可以使业务更 ...

  9. R学习笔记 第四篇:函数,分支和循环

    变量用于临时存储数据,而函数用于操作数据,实现代码的重复使用.在R中,函数只是另一种数据类型的变量,可以被分配,操作,甚至把函数作为参数传递给其他函数.分支控制和循环控制,和通用编程语言的风格很相似, ...

随机推荐

  1. 多线程爬坑之路-学习多线程需要来了解哪些东西?(concurrent并发包的数据结构和线程池,Locks锁,Atomic原子类)

    前言:刚学习了一段机器学习,最近需要重构一个java项目,又赶过来看java.大多是线程代码,没办法,那时候总觉得多线程是个很难的部分很少用到,所以一直没下决定去啃,那些年留下的坑,总是得自己跳进去填 ...

  2. 如何一步一步用DDD设计一个电商网站(七)—— 实现售价上下文

    阅读目录 前言 明确业务细节 建模 实现 结语 一.前言 上一篇我们已经确立的购买上下文和销售上下文的交互方式,传送门在此:http://www.cnblogs.com/Zachary-Fan/p/D ...

  3. servlet文件下载

    创建web工程servlet,新建DownloadServlet.java package com.xmyself.servlet; import java.io.File; import java. ...

  4. 漫扯:从polling到Websocket

    Http被设计成了一个单向的通信的协议,即客户端发起一个request,然后服务器回应一个response.这让服务器很为恼火:我特么才是老大,我居然不能给小弟发消息... 轮询 老大发火了,小弟们自 ...

  5. ASP.NET MVC5+EF6+EasyUI 后台管理系统(1)-前言与目录(持续更新中...)

    开发工具:VS2015(2012以上)+SQL2008R2以上数据库  您可以有偿获取一份最新源码联系QQ:729994997 价格 666RMB  升级后界面效果如下: 任务调度系统界面 http: ...

  6. DBA成长路线

    从开发转为数据库管理,即人们称为DBA的已经有好几年,有了与当初不一样的体会.数据是企业的血液,数据是石油,数据是一切大数据.云计算的基础.作为DBA是数据的保卫者.管理者,是企业非常重要的角色.对于 ...

  7. JavaScript特性(attribute)、属性(property)和样式(style)

    最近在研读一本巨著<JavaScript忍者秘籍>,里面有一篇文章提到了这3个概念. 书中的源码可以在此下载.我将源码放到了线上,如果不想下载,可以直接访问在线网址,修改页面名就能访问到相 ...

  8. JavaWeb——Servlet

    一.基本概念 Servlet是运行在Web服务器上的小程序,通过http协议和客户端进行交互. 这里的客户端一般为浏览器,发送http请求(request)给服务器(如Tomcat).服务器接收到请求 ...

  9. ,net core mvc 文件上传

    工作用到文件上传的功能,在这个分享下 ~~ Controller: public class PictureController : Controller { private IHostingEnvi ...

  10. Linux下编译安装Vim8.0

    什么是Vim? Vim 是经典的 UNIX 编辑器 Vi 的深度改良版本.它增加了许多功能,包括:多级撤销.格式高亮.命令行历史.在线帮助.拼写检查.文件名补完.块操作.脚本支持,等等.除了字符界面版 ...