购买
下载掌阅APP,畅读海量书库
立即打开
畅读海量书库
扫码下载掌阅APP

2.1 流程控制

程序有时只能按照编写的顺序执行,中途不能发生任何变化。然而实际生活中并非所有的事情都是按部就班地进行,程序也是一样。为了适应需要,经常必须转移或者改变程序执行的顺序,达到这些目的的语句叫作流程控制语句。和大多数编程语言相似,在程序模块中,C#可以通过条件语句控制程序的流程,从而形成程序的分支和循环。C#中提供了以下控制关键字:

1)选择控制:if else、switch

2)循环控制:while、do-while、for、foreach

3)跳转语句:break、continue

4)编译控制:#if、#elif、#else、#endif

5)异常处理:try、catch、finally

2.1.1 条件语句

当程序中需要进行两个或两个以上的选择时,可以根据条件判断来选择将要执行的一组语句,C#提供的选择语句有if语句和switch语句。

2.1.1.1 if语句

if语句是最常用的选择语句,它根据布尔表达式的值来判断是否执行后面的内嵌语句格式,其形式为

当布尔表达式的值为真,则执行if后面的内嵌语句embedded-statement;当布尔表达式的值为假,则程序继续执行。如果有else语句,则执行else后面的内嵌语句,否则继续执行下一条语句。

例如下面的例子用来对一个浮点数x进行四舍五入,结果保存到一个整数i中:

如果if或else之后的嵌套语句只包含一条执行语句,则嵌套部分的大括号可以省略;如果包含了两条以上的执行语句,对嵌套部分一定要加上大括号;如果程序的逻辑判断关系比较复杂,通常会采用条件判断嵌套语句,if语句可以嵌套使用,即在判断之中又有判断,具体形式如下:

此时应该注意每一条else与离它最近且没有其他else与之对应的if相搭配,比如有下面一条语句:

它实际上应该等价于下面的写法:

注意C#的if语句与C、C++不同,即if后的逻辑表达式必须是布尔类型的。

请看一个判断是否往应用程序传送参数的例子:

程序清单 2-1:

其中args.Length==0是一个布尔表达式,但是C或者C++程序员可能会习惯编写像这样的代码:

这在C#中是不允许的,因为if语句仅允许布尔类型的结果,而字符串的Length属性对象返回一个整型(integer),编译器将报告错误信息。

2.1.1.2 switch语句

if语句每次判断只能实现两条分支,如果要实现多种选择的功能,那么可以采用switch语句。switch语句根据一个控制表达式的值选择一个内嵌语句分支来执行。它的一般格式为

switch语句的控制类型,即其中控制表达式(controlling-expression)的数据类型可以是sbyte、byte、short、ushort、uint、long、ulong、char、string或枚举类型(enum-type)。每个case标签中的常量表达式(constant-expression)必须属于或能隐式转换成控制类型,如果有两个或两个以上case标签中的常量表达式值相同,编译时将会报错。switch语句中最多只能有一个default标签。我们举一个例子来说明switch语句是如何实现程序的多路分支的:假设考查课的成绩按优秀、良好、中等、及格和不及格分为五等,分别用4、3、2、1、0来表示,但实际的考卷为百分制,对应的分数分别为90~100、80~89、70~79、60~69、60分以下。下面的程序将考卷成绩x转换为考查课成绩y,代码如下:

下面的例子判断传递给应用程序的参数的有无及位数:

程序清单 2-2:

使用switch语句时需注意以下两点:

1.不准遍历

C和C++语言允许switch语句中case标签后不出现break语句,但C#不允许这样,它要求每个标签项后使用break语句或跳转语句goto,即不允许从一个case自动遍历到其他case,否则编译时将报错。

一个程序用于计算一年中已度过的天数,month表示月份,day表示日期,计算结果保存在total中。为简便起见把闰年的情况排除在外,C和C++程序员会利用一点技巧来实现这个程序:

然而这种写法在C#中是不允许的。很难保证任何人在编程时都不会忘记在case后加上break语句,这时往往会造成一些不易察觉的错误,所以在C#中如果标签项没有出现break语句或跳转语句goto,编译器将会要求程序员加上。

如果想像C、C++那样,执行完后继续遍历其他的语句,那也不难,只需要明确地加入这两条跳转语句即可:

➢ goto case label:跳至标签语句执行

➢ goto default:跳至default标签执行

那样上面的程序可以改写为

在避免了C、C++中常出现的由于漏写break而造成的错误的同时不准遍历的原则,还使得我们可以任意排列switch语句中的case项而不会影响switch语句的功能。另外,一般说来每个switch项都以break、goto、case或goto、default结束,但实际上任何一种不导致遍历的结构都是允许的,例如throw和return语句同样可以跳出控制之外,因而下例是正确的:

2.把字符串当成常量表达式

VB的程序员可能已经习惯把字符串当成常量表达式来使用,但C和C++却不支持这一点,C#的switch语句与C、C++的另一个不同点是:C#可以把字符串当成常量表达式来使用,所以switch语句的控制类型可以是string类型。

下面的例子实现浮动窗口提示。在Windows操作系统中,把鼠标移到某一个控件上停留几秒,将会出现一个浮动提示,说明该控件的作用。例子中的GetButtonCaption用于获得按钮上的文字,ShowMessage表示在浮动提示窗口中显示信息:

2.1.2 循环语句

循环语句可以实现一个程序模块的重复执行,它对于简化程序、更好地组织算法有着重要的意义。C#提供了四种循环语句,分别适用于不同的情形:while语句、do-while语句、for语句、foreach语句。

2.1.2.1 while语句

while语句有条件地将内嵌语句执行0遍或若干遍,语句的格式为

它的执行顺序是:

1)计算布尔表达式boolean-expression的值。

2)当布尔表达式的值为真时,执行内嵌语句embedded-statement一遍,程序转至第1)步。

3)当布尔表达式的值为假时,while循环结束。

下面来看一个简单的例子,该例在数组中查找一个指定的值,如找到就返回数组下标,否则返回并报告。

程序清单 2-3:

while语句中允许使用break语句结束循环,执行后续语句;也可以用continue语句来停止内嵌语句的执行,继续进行while循环。

我们使用下面的程序片段来计算一个整数x的阶乘值:

2.1.2.2 do-while语句

do-while语句与while语句不同的是:它将内嵌语句执行至少一遍。语句的格式为

它按如下顺序执行:

1)执行内嵌语句embedded-statement一遍。

2)计算布尔表达式boolean-expression的值,为true则回到第1)步,为false则终止do循环。在do-while循环语句同样允许用break语句和continue语句实现与while语句中相同的功能。

我们看一下如何使用do-while循环来实现求整数的阶乘:

2.1.2.3 for语句

for语句是C#中使用频率最高的循环语句,在事先知道循环次数的情况下使用for语句是比较方便的。for语句的格式为

其中,initializer、condition、iterator这三项都是可选项:initializer为循环控制变量做初始化,循环控制变量可以有一个或多个(用逗号隔开);condition为循环控制条件,也可以有一个或多个语句;iterator按规律改变循环控制变量的值。应注意初始化循环控制条件和循环控制都是可选的。如果忽略了条件,就会产生死循环,要用跳转语句break或goto才能退出。

for语句执行顺序如下:

1)按书写顺序将initializer部分(如果有的话)执行一遍,为循环控制变量赋初值。

2)测试condition(如果有的话)中的条件是否满足。

3)若没有condition项或条件满足,则执行内嵌语句一遍,按iterator改变循环控制变量的值回到第2)步执行。

4)若条件不满足则for循环终止。

下面的例子非常简单,打印数字1到9,但它却清楚地显示出了for语句是怎样工作的:

for语句可以嵌套使用,帮助我们完成大量重复性、规律性的工作。

下面的例子用于打印杨辉三角形:

程序清单 2-4:

运行程序的结果为

还以求整数的阶乘为例,代码可以这样写:

同样可以用break和continue语句来和循环判断符合语句中的逻辑表达式配合使用达到控制循环的目的。仍然以打印数字为例,如果要求打印除7以外的0到9之间的数字,只要在for循环执行到7时,跳过打印语句就可以了。

2.1.2.4 foreach语句

foreach语句是在C#中新引入的,C和C++中没有这个语句,而Visual Basic的程序员应该对它不会陌生,它表示收集一个集合中的各元素,并针对各个元素执行内嵌语句。语句的格式为

其中,类型(type)和标识符(identifier)用来声明循环变量表达式(expression)对应集合,每执行一次内嵌语句,循环变量就依次取集合中的一个元素,代入其中。在这里,循环变量是一个只读型局部变量,如果试图改变它的值或将它作为一个ref或out类型的参数传递,都将引发编译时错误。

foreach语句中的expression必须是集合类型,如果该集合的元素类型与循环变量类型不一致,则必须将集合中的元素类型显式转换为循环变量元素类型。

集合表示一组相同或相似的数据项总的描述。那么在C#中究竟什么样的类型算是集合类型呢?我们从语法上给出集合类型的定义:

1)该类型必须支持一个形为GetEnumerator的公有的非静态方法,该方法的返回类型为结构类或接口。

2)形为GetEnumerator的方法,返回的结构类或接口应当包含一个公有的非静态的方法MoveNext,该方法的返回类型为布尔型。

3)形为GetEnumerator的方法,返回的结构类或接口应当包含一个公有的非静态的属性Current,该属性可以读出。

如果一个类型同时满足以上三个条件,该类型称为集合类型,Current属性的类型叫作该集合类型的元素类型。

我们姑且不论集合类型的具体形式,只从foreach语句的使用角度举一个例子。假设Prime是一个满足条件的集合类型,它的元素类型为1000以内的质数,MyInt是我们自定义的一个类型,其范围为200到300之间的整数。下面这段程序用于在屏幕上显示出从200到300之间的所有质数:

程序清单 2-5:

顺便说一句,数组类型是支持foreach语句的。对于一维数组执行顺序是从下标为0的元素开始,一直到数组的最后一个元素。对于多维数组元素,下标的递增是从最右边那一维开始的,依此类推。同样break和continue可以出现在foreach语句中,功能不变。 zfA4RVdSxV6fGtm2pjg+mrX5iR/dYqJjjRQr+kq0yQtSa3TxDOf877djD6r1oTMb

点击中间区域
呼出菜单
上一章
目录
下一章
×