本文讨论流程控制代码结构中的循环语句、break语句、continue语句、goto语句和标签,以及如何使用try语句处理运行时错误(异常)。
for语句可以根据已知的数值条件重复执行相同的代码,其结构如下:
for (<初始化循环控制变量>; <条件>; <每次循环的变化>) { <循环语句> }
其中,<初始化循环控制变量>会声明循环控制变量并设置初始值。<条件>指定循环的条件。<每次循环的变化>指定每次循环后控制变量的变化。如下面的代码会计算1到100的累加。
using System; namespace csfx_demo { class Program { static void Main(string[] args) { int sum = 0; for(int i = 1; i <= 100; i++) { sum += i; } // Console.WriteLine(sum); } } }
本例,使用变量i控制循环的次数,同时也是加数的数据,其初始值为1,每次执行循环语句后会使用自增量运算符(++)加1,当其值小于等于100时会执行循环语句,大于100后会终止for语句结构的执行。循环语句中,会将i的值累加到sum变量中。执行代码会显示5050。
foreach语句可以逐一访问集合元素,如数组、列表、字典等类型中的元素,在循环语句中,可以通过相同的代码处理这些元素。其应用结构如下:
foreach(<元素类型> <元素变量> in <集合对象>) { <循环语句> }
下面的代码演示了数组元素的显示。
using System; namespace csfx_demo { class Program { static void Main(string[] args) { int[] arr = new int[] { 1, 1, 2, 3, 5, 8 }; foreach(int n in arr) { Console.WriteLine(n); } } } }
执行代码会依次显示1、1、2、3、5、8。
while语句结构会根据指定的条件重复执行代码,应用结构如下。
while (<条件>) { <循环语句> }
while语句结构中,当<条件>为true时会重复执行<循环语句>,请注意,<循环语句>中应该有改变条件的语句,否则会无限循环,也称为“死循环”。
下面的语句会使用while语句计算1到100的累加。
using System; namespace csfx_demo { class Program { static void Main(string[] args) { int n = 1; int sum = 0; while (n <= 100) { sum += n; n++; } // Console.WriteLine(sum); // 5050 } } }
代码中,使用变量n定义循环条件变量,并设置初始值为1;while语句中,当n小于等于100时执行循环语句,当n大于100时会停止执行while语句结构。循环语句中,首先将n的值累加到sum变量中,然后n加1。最终显示结果为5050。
do...while语句与while语句相似,区别在于,do...while语句结构会将条件的判断放在每次循环语句执行之后,应用结构如下。
do { <循环语句> } while (<条件>);
下面的代码使用do...while语句实现1到100的累加。
using System; namespace csfx_demo { class Program { static void Main(string[] args) { int n = 1; int sum = 0; do { sum += n; n++; } while (n <= 100); // Console.WriteLine(sum); // 5050 } } }
实际工作中,大多数情况下会使用while语句结构,即在每次循环之前进行条件的判断,以防发生因条件不满足而产生的异常。do...while语句结构中,至少会执行一次循环语句,需要注意第一次执行循环语句时可能出现的问题。
break语句除了在switch语句中终止case和default语句块,还可以立即终止循环语句,如下面的代码会判断大于1的整数是否为质数(素数)。
using System; namespace csfx_demo { class Program { static void Main(string[] args) { int n = 3; bool result = true; int max = (int)Math.Ceiling(Math.Sqrt(n)); for (int i = 2; i <= max; i++) { if (n % i == 0) { result = false; break; } } // if (result) Console.WriteLine("{0}是质数", n); else Console.WriteLine("{0}不是质数", n); } } }
代码中,变量n指定需要判断是否为质数的整数。变量result为判断结果,这里设置初始值为true,与下面的代码配合使用。变量max获取n的平方根向上取整的值,作为循环控制变量的最大值。判断整数是不是质数时,只要数值n能够被2到max中的一个整数整除,它就不是质数,此时将result设置false,并使用break语句立即终止for循环结构。可修改变量n的值来观察执行结果。
关于工作中常用的数学计算代码,除了System.Math类中提供的资源,也可以封装自己的代码,如下面的代码(/cfx/Calc.cs)。
using System; namespace cfx { public static class Calc { // 判断是否为质数 public static bool IsPrime(long n) { if (n < 2) return false; long max = (long)Math.Ceiling(Math.Sqrt(n)); for (int i = 2; i <= max; i++) { if (n % i == 0) { return false; } } return true; } } }
代码中,在cfx命名空间中定义了Calc静态类,并定义IsPrime()方法,用于判断参数带入的整数是否为质数。代码中,当数值能够被2到其平方根之间的整数整除时,直接使用return语句返回false,循环结束后,即没有被2到其平方根之间的整数整除时,参数带入的整数就是质数,方法会返回true。
在循环语句结构中,continue语句可以停止本次循环,并在满足条件的情况下开始下一次循环,如下面的代码会计算1到100中偶数的累加。
using System; namespace csfx_demo { class Program { static void Main(string[] args) { int sum = 0; for(int i = 1; i <= 100; i++) { if (i % 2 != 0) continue; else sum += i; } // Console.WriteLine(sum); // 2550 } } }
for语句结构中,当i不是偶数时会使用continue语句停止当前循环,当i是偶数时则累加到sum变量中,结果会显示2550。
实际上,对于这种有规律的数值控制条件,可以进一步简化操作,如下面的代码。
using System; namespace csfx_demo { class Program { static void Main(string[] args) { int sum = 0; for(int i = 2; i <= 100; i+=2) { sum += i; } // Console.WriteLine(sum); // 2550 } } }
代码中修改了循环控制变量的初始值为2,并修改了每次循环后i加2,这样就读取了2到100中的所有偶数,循环语句中将偶数逐一累加到sum变量中,计算结果为2550。
代码中,可以为代码块定义一个标签,格式为“<标签名>:”,然后使用“goto <标签名>”语句跳转到指定的标签。
下面的代码,使用goto和标签模拟循环操作。
using System; namespace csfx_demo { class Program { static void Main(string[] args) { int n = 1; int sum = 0; // label1: { sum += n; n++; if (n <= 100) goto label1; } // Console.WriteLine(sum); // 5050 } } }
代码中同样执行的是1到100的累加操作,标签label1定义了类似循环语句的代码块,其中,会将n的值累加到sum,然后加1,当n小于等于100时会跳转到label1标签的位置,重复执行累加操作,直到n大于100时会继续向下执行,即显示累加结果。
try...catch...finally语句结构的基本应用格式如下:
try { <语句0> } catch(<异常1>) { <语句1> } catch(<异常2>) { <语句2> } catch { <语句3> } finally { <语句n> }
如代码所示,try语句块中的<语句0>是主代码块。catch语句块可以有多个或者没有,catch关键字后可以使用一对圆括号定义具体的异常类型,当<语句0>中的代码产生运行时错误(异常)时会执行对应的处理代码;没有参数的catch代码块统一处理捕捉到的异常。无论<语句0>的代码是否产生异常,最终都会执行finally块中的语句。
在此结构中,try块是必须的,然后至少包含一个catch代码块或finally代码块;包含具体异常类型的catch代码可以有多个,也可以没有;没有包含具体异常类型的catch只能有一个或者没有,没有指定catch代码块时必须使用finally代码块。
下面的代码演示了捕捉除零错误。
using System; namespace csfx_demo { class Program { static void Main(string[] args) { try { int x = 10, y = 0; Console.WriteLine(x / y); } catch(DivideByZeroException ex) { Console.WriteLine(ex.Message); } } } }
执行代码结果如下图所示。
下面的代码演示了通用catch代码块与finally代码块的应用。
using System; namespace csfx_demo { class Program { static void Main(string[] args) { try { int x = 10, y = 0; Console.WriteLine(x / y); } catch { Console.WriteLine("产生异常"); } finally { Console.WriteLine("finally语句块"); } } } }
执行结果如下图所示。
代码中,当变量y不为0时,会显示x除以y的结果并执行finally块的代码,比如,将y修改为2时,执行结果如下图所示。