C#循环语句与try语句

本文讨论流程控制代码结构中的循环语句、break语句、continue语句、goto语句和标签,以及如何使用try语句处理运行时错误(异常)。

for语句

for语句可以根据已知的数值条件重复执行相同的代码,其结构如下:

C#
for (<初始化循环控制变量>; <条件>; <每次循环的变化>)
{
    <循环语句>
}

其中,<初始化循环控制变量>会声明循环控制变量并设置初始值。<条件>指定循环的条件。<每次循环的变化>指定每次循环后控制变量的变化。如下面的代码会计算1到100的累加。

C#
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语句可以逐一访问集合元素,如数组、列表、字典等类型中的元素,在循环语句中,可以通过相同的代码处理这些元素。其应用结构如下:

C#
foreach(<元素类型> <元素变量> in <集合对象>)
{
    <循环语句>
}

下面的代码演示了数组元素的显示。

C#
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语句结构会根据指定的条件重复执行代码,应用结构如下。

C#
while (<条件>)
{
    <循环语句>
}

while语句结构中,当<条件>为true时会重复执行<循环语句>,请注意,<循环语句>中应该有改变条件的语句,否则会无限循环,也称为“死循环”。

下面的语句会使用while语句计算1到100的累加。

C#
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语句

do...while语句与while语句相似,区别在于,do...while语句结构会将条件的判断放在每次循环语句执行之后,应用结构如下。

C#
do
{
    <循环语句>
} while (<条件>);

下面的代码使用do...while语句实现1到100的累加。

C#
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语句

break语句除了在switch语句中终止case和default语句块,还可以立即终止循环语句,如下面的代码会判断大于1的整数是否为质数(素数)。

C#
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)。

C#
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语句

在循环语句结构中,continue语句可以停止本次循环,并在满足条件的情况下开始下一次循环,如下面的代码会计算1到100中偶数的累加。

C#
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。

实际上,对于这种有规律的数值控制条件,可以进一步简化操作,如下面的代码。

C#
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 <标签名>”语句跳转到指定的标签。

下面的代码,使用goto和标签模拟循环操作。

C#
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...catch...finally语句结构的基本应用格式如下:

C#
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代码块。

下面的代码演示了捕捉除零错误。

C#
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代码块的应用。

C#
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语句块");
            }
        }
    }
}

执行结果如下图所示。

通知catch语句块和finally语句块

代码中,当变量y不为0时,会显示x除以y的结果并执行finally块的代码,比如,将y修改为2时,执行结果如下图所示。

finally语句块