ZetCode

C# 流程控制

上次修改时间:2024 年 1 月 19 日

在本文中,我们将讨论 C# 中的流程控制。我们将定义几个关键字,使我们能够控制 C# 程序的流程。

当运行 C# 程序时,代码从上到下执行。程序的流程可以通过各种关键字来改变,包括 if/else、for、while 和 switch。

控制流结构可用于有条件地或多次执行代码。

C# if 语句

if 语句具有以下通用形式

if (expression)
{
    statement;
}

if 关键字用于检查表达式是否为真。如果为真,则执行语句。该语句可以是单个语句或复合语句。复合语句由块中包含的多个语句组成。块是由花括号括起来的代码。

Program.cs
var r = new Random();
int n = r.Next(-5, 5);

Console.WriteLine(n);

if (n > 0)
{
    Console.WriteLine("The n variable is positive");
}
 

生成一个随机数。如果该数字大于零,我们向终端打印一条消息。

var r = new Random();
int n = r.Next(-5, 5);

这两行代码生成一个 -5 到 5 之间的随机整数。

if (n > 0)
{
    Console.WriteLine("The n variable is positive");
}

使用 if 关键字,我们检查生成的数字是否大于零。if 关键字后跟一对圆括号。在圆括号内,我们放置一个表达式。表达式的结果是一个布尔值。如果布尔值为真,则执行由两个花括号括起来的块。

在我们的例子中,字符串 "The n variable is positive" 被打印到终端。如果随机值为负数,则不执行任何操作。如果我们只有一个表达式,则花括号是可选的。

$ dotnet run
-3
$ dotnet run
-4
$ dotnet run
-1
$ dotnet run
1
The n variable is positive

当满足条件时,消息将被写入控制台。

C# else 语句

我们可以使用 else 关键字来创建一个简单的分支。如果 if 关键字后面的方括号内的表达式的计算结果为假,则自动执行 else 关键字后面的语句。

Program.cs
var r = new Random();
int n = r.Next(-5, 5);

Console.WriteLine(n);

if (n > 0)
{
    Console.WriteLine("The number is positive");
} else
{
    Console.WriteLine("The number is negative");
}

要么执行 if 关键字后面的块,要么执行 else 关键字后面的块。

if (n > 0)
{
    Console.WriteLine("The number is positive");
} else
{
    Console.WriteLine("The number is negative");
}

else 关键字跟在 if 块的右花括号后面。它有自己的块,由一对花括号括起来。

$ dotnet run
-3
The number is negative
$ dotnet run
-1
The number is negative
$ dotnet run
2
The number is positive

我们执行该程序三次。

C# else if

我们可以使用 else if 关键字创建多个分支。只有在前一个条件未满足时,else if 关键字才会测试另一个条件。请注意,我们可以在测试中使用多个 else if 关键字。

Program.cs
var r = new Random();
int n = r.Next(-5, 5);

Console.WriteLine(n);

if (n < 0)
{
    Console.WriteLine("The n variable is negative");
} else if (n == 0)
{
    Console.WriteLine("The n variable is zero");

} else
{
    Console.WriteLine("The n variable is positive");
}

之前的程序有一个小问题。零被赋给负值。以下程序将修复此问题。

if (n < 0)
{
    Console.WriteLine("The n variable is negative");
} else if (n == 0)
{
    Console.WriteLine("The n variable is zero");
} else
{
    Console.WriteLine("The n variable is positive");
}

如果第一个条件的计算结果为真,例如,输入的值小于零,则执行第一个块,并跳过剩余的两个块。如果第一个条件不满足,则检查 if else 关键字后面的第二个条件。如果第二个条件的计算结果为真,则执行第二个块。如果不是,则执行 else 关键字后面的第三个块。如果之前的条件都不满足,则始终执行 else 块。

$ dotnet run
-1
The n variable is negative
$ dotnet run
4
The n variable is positive
$ dotnet run
1
The n variable is positive
$ dotnet run
0
The n variable is zero

我们执行该程序三次。0 被正确处理。

C# switch 语句

switch 语句是一个选择控制流程语句。它允许变量或表达式的值通过多路分支来控制程序执行的流程。它以比使用 if/else if/else 语句的组合更简单的方式创建多个分支。

我们有一个变量或一个表达式。switch 关键字用于根据值的列表测试变量或表达式中的值。值的列表用 case 关键字表示。如果值匹配,则执行 case 后面的语句。有一个可选的 default 语句。如果找不到其他匹配项,则执行该语句。

自 C# 7.0 以来,匹配表达式可以是任何非空表达式。

选择星期几

在以下示例中,我们使用 switch 语句选择星期几。

Program.cs
var dayOfWeek = DateTime.Now.DayOfWeek;

switch (dayOfWeek)
{
    case DayOfWeek.Sunday:
        Console.WriteLine("dies Solis");
        break;

    case DayOfWeek.Monday:
        Console.WriteLine("dies Lunae");
        break;

    case DayOfWeek.Tuesday:
        Console.WriteLine("dies Martis");
        break;

    case DayOfWeek.Wednesday:
        Console.WriteLine("dies Mercurii");
        break;

    case DayOfWeek.Thursday:
        Console.WriteLine("dies Jovis");
        break;

    case DayOfWeek.Friday:
        Console.WriteLine("dies Veneris");
        break;

    case DayOfWeek.Saturday:
        Console.WriteLine("dies Saturni");
        break;
}

该示例确定当前星期几并打印其拉丁语等价物。

switch (dayOfWeek)
{
    ...
}

在圆括号中,switch 关键字从表达式中获取一个值,该值将被测试。switch 关键字的主体放置在一对或花括号内。在主体中,我们可以放置多个 case 选项。每个选项都以 break 关键字结尾。

case DayOfWeek.Sunday:
    Console.WriteLine("dies Solis");
    break;

使用 case 语句,我们测试匹配表达式的值。如果它等于 DayOfWeek.Sunday,我们打印拉丁语 dies Solis

$ dotnet run
dies Solis

该程序在星期日运行。

选择域名

要求用户输入域名。域名被读取并存储在一个变量中。使用 switch 关键字针对选项列表测试该变量。

Program.cs
Console.Write("Enter a domain name: ");

string domain = Console.ReadLine();

domain = domain.Trim().ToLower();

switch (domain)
{
    case "us":
        Console.WriteLine("United States");
    break;

    case "de":
        Console.WriteLine("Germany");
    break;

    case "sk":
        Console.WriteLine("Slovakia");
    break;

    case "hu":
        Console.WriteLine("Hungary");
    break;

    default:
        Console.WriteLine("Unknown");
    break;
}

在我们的程序中,我们有一个 domain 变量。我们从命令行读取变量的值。我们使用 case 语句来测试变量的值。有几个选项。如果该值等于例如 "us",则将字符串 "United States" 打印到控制台。

string domain = Console.ReadLine();

来自用户的输入是从控制台读取的。

domain = domain.Trim().ToLower();

Trim 方法从变量中删除潜在的前导和尾随空格。ToLower 将字符转换为小写。现在 "us"、"US"、"us " 是 us 域名可行的选项。

case "us":
    Console.WriteLine("United States");
break;

在此 case 选项中,我们测试 domain 变量是否等于 "us" 字符串。如果为真,我们将消息打印到控制台。该选项以 break 关键字结尾。如果成功评估其中一个选项,则 break 关键字将终止 switch 块。

default:
    Console.WriteLine("Unknown");
break;

default 关键字是可选的。如果未评估任何 case 选项,则执行 default 部分。

$ dotnet run
Enter a domain name: us
United States

$ dotnet run
Enter a domain name: HU
Hungary

$ dotnet run
Enter a domain name: pl
Unknown

使用 when 语句

case 语句可以与 when 语句一起使用以指定附加条件。

Program.cs
Console.Write("Enter your age: ");

var input = Console.ReadLine();

var age = Int32.Parse(input.Trim());

switch (age)
{
    case var myAge when myAge < 0:
        Console.WriteLine("Age cannot be a negative value");
    break;

    case var myAge when myAge > 130:
        Console.WriteLine("This is an unlikely high age");
    break;

    default:
        Console.WriteLine("The entered age is {0}", age);
    break;
}

在该程序中,要求用户输入他的年龄。

case var myAge when myAge < 0:
    Console.WriteLine("Age cannot be a negative value");
break;

借助 when 表达式,我们测试输入的值是否小于 0。使用 var 关键字,我们创建一个临时的 myAge 变量。

使用枚举作为匹配表达式

对于匹配表达式,我们可以使用任何类型。在以下示例中,我们使用枚举。

Program.cs
var color = (Color) (new Random()).Next(0, 7);

switch (color)
{
    case Color.Red:
        Console.WriteLine("The color is red");
        break;

    case Color.Green:
        Console.WriteLine("The color is green");
        break;

    case Color.Blue:
        Console.WriteLine("The color is blue");
        break;

    case Color.Brown:
        Console.WriteLine("The color is brown");
        break;

    case Color.Yellow:
        Console.WriteLine("The color is yellow");
        break;

    case Color.Pink:
        Console.WriteLine("The color is pink");
        break;

    case Color.Orange:
        Console.WriteLine("The color is orange");
        break;

    default:
        Console.WriteLine("The color is unknown.");
        break;
}

enum Color { Red, Green, Blue, Brown, Yellow, Pink, Orange }

该示例随机生成一个颜色枚举。swith 语句确定生成了哪个颜色值。

$ dotnet run
The color is orange

$ dotnet run
The color is blue

$ dotnet run
The color is brown

我们运行该程序。

Switch 表达式

Switch 表达式使 switch 语句的语法更加简洁。它们是在 C# 8.0 中引入的。

Program.cs
Console.Write("Enter a domain name: ");

string domain = Console.ReadLine();

domain = domain.Trim().ToLower();

string result = domain switch
{
    "us" => "United States",
    "de" => "Germany",
    "sk" => "Slovakia",
    "hu" => "Hungary",

    _ => "Unknown"
};

Console.WriteLine(result);

变量位于 switch 关键字之前。case: 元素被 => 替换。default case 被 _ 丢弃替换。主体是表达式,而不是语句。

C# while 语句

while 语句是一个控制流程语句,允许根据给定的布尔条件重复执行代码。

while (expression)
{
    statement;
}

while 关键字执行大括号括起来的块内的语句。只要表达式的计算结果为 true,就会执行这些语句。

Program.cs
int i = 0;
int sum = 0;

while (i < 10)
{
    i++;
    sum += i;
}

Console.WriteLine(sum);

在代码示例中,我们计算某个数字范围内值的总和。

while 循环有三个部分。初始化、测试和更新。语句的每次执行都称为一个周期。

int i = 0;

我们初始化 i 变量。它用作计数器。

while (i < 10)
{
   ...
}

while 关键字后面的圆括号内的表达式是第二阶段,即测试。主体中的语句将一直执行,直到表达式的计算结果为假。

i++;

这是 while 循环的最后一个第三阶段,即更新。我们递增计数器。请注意,不正确地处理 while 循环可能会导致无限循环。

Do-while 语句

可以至少运行一次该语句。即使不满足条件也是如此。为此,我们可以使用 do while 关键字。

Program.cs
int count = 0;

do {
    Console.WriteLine(count);
} while (count != 0);

首先执行该块,然后评估真值表达式。在我们的例子中,不满足条件,并且 do while 语句终止。

C# for 语句

如果在循环开始之前知道循环次数,我们可以使用 for 语句。在此构造中,我们声明一个计数器变量,该变量在循环的每次重复期间自动增加或减少值。

简单 for 循环

for 循环有三个阶段:初始化、条件和代码块执行,以及递增。

Program.cs
for (int i = 0; i < 10; i++)
{
    Console.WriteLine(i);
}

在此示例中,我们将数字 0..9 打印到控制台。

for (int i = 0; i < 10; i++)
{
    Console.WriteLine(i);
}

有三个阶段。在第一阶段,我们将计数器 i 初始化为零。此阶段仅完成一次。接下来是条件。如果满足条件,则执行 for 块内的语句。在第三阶段,计数器递增。现在我们重复第 2, 3 阶段,直到不满足条件并且退出 for 循环。在我们的例子中,当计数器 i 等于 10 时,for 循环停止执行。

For 循环数组遍历

for 循环可用于遍历数组。从数组的 Length 属性,我们知道数组的大小。

Program.cs
string[] planets = [ "Mercury", "Venus", "Earth",
    "Mars", "Jupiter", "Saturn", "Uranus", "Pluto" ];

for (int i = 0; i < planets.Length; i++)
{
    Console.WriteLine(planets[i]);
}

Console.WriteLine("In reverse:");

for (int i = planets.Length - 1; i >= 0; i--)
{
    Console.WriteLine(planets[i]);
}

我们有一个数组,其中包含太阳系中行星的名称。使用两个 for 循环,我们按升序和降序打印这些值。

for (int i = 0; i < planets.Length; i++)
{
    Console.WriteLine(planets[i]);
}

通过从零开始的索引访问数组。第一个项目的索引为 0。因此,i 变量初始化为零。该条件检查 i 变量是否小于数组的长度。在最后阶段,i 变量递增。

for (int i = planets.Length - 1; i >= 0; i--)
{
    Console.WriteLine(planets[i]);
}

此 for 循环按相反的顺序打印数组的元素。i 计数器初始化为数组大小。由于索引是从零开始的,因此最后一个元素的索引为数组大小 - 1。该条件确保计数器大于或等于零。(数组索引不能为负数)。在第三步中,i 计数器递减 1。

for 循环中更多的表达式

可以在 for 循环的初始化和迭代阶段放置更多的表达式。

Program.cs
var r = new Random();
var values = new int[10];

int sum = 0;
int num = 0;

for (int i = 0; i < 10; i++, sum += num)
{
    num = r.Next(10);
    values[i] = num;
}

Console.WriteLine(string.Join(",", values));
Console.WriteLine("The sum of the values is {0}", sum);

在我们的示例中,我们创建一个包含十个随机数的数组。计算这些数字的总和。

for (int i = 0; i < 10; i++, sum += num)
{
    num = r.Next(10);
    values[i] = num;
}

在 for 循环的第三部分中,我们有两个表达式,用逗号字符分隔。i 计数器递增,并且将当前数字添加到 sum 变量中。

Console.WriteLine(string.Join(",", values));

使用 System.String 类的 Join 方法,我们可以一次性打印数组的所有值。它们将用逗号字符分隔。

$ dotnet run
9,3,1,7,9,8,5,6,3,3
The sum of the values is 54

嵌套 for 循环

For 语句可以嵌套;即,for 语句可以放置在另一个 for 语句中。对于外部 for 循环的每个周期,都会执行嵌套 for 循环的所有周期。

Program.cs
string[] a1 = ["A", "B", "C"];
string[] a2 = ["A", "B", "C"];

for (int i = 0; i < a1.Length; i++)
{
    for (int j = 0; j < a2.Length; j++)
    {
        Console.WriteLine(a1[i] + a2[j]);
    }
}

在此示例中,我们创建两个数组的笛卡尔积。

string[] a1 = ["A", "B", "C"];
string[] a2 = ["A", "B", "C"];

我们有两个数组。每个数组都有三个字母。当一个数组中的每个元素与另一个数组中的所有元素配对时,就形成笛卡尔积。为了实现此目的,我们使用嵌套的 for 循环。

for (int i = 0; i < a1.Length; i++)
{
    for (int j = 0; j < a2.Length; j++)
    {
        Console.WriteLine(a1[i] + a2[j]);
    }
}

在一个父 for 循环内部有一个嵌套的 for 循环。对于父 for 循环的每个周期,都会完全执行嵌套的 for 循环。

$ dotnet run
AA
AB
AC
BA
BB
BC
CA
CB
CC

C# foreach 语句

foreach 构造简化了对数据集合的遍历。它没有显式计数器。foreach 语句逐个遍历数组或集合,并将当前值复制到构造中定义的变量中。

Program.cs
string[] planets = [ "Mercury", "Venus", "Earth", "Mars", "Jupiter",
    "Saturn", "Uranus", "Neptune" ];

foreach (string planet in planets)
{
    Console.WriteLine(planet);
}

在此示例中,我们使用 foreach 语句来遍历行星数组。

foreach (string planet in planets)
{
    Console.WriteLine(planet);
}

foreach 语句的用法非常简单。planets 是我们迭代的数组。planet 是一个临时变量,它具有数组中的当前值。foreach 语句遍历所有行星并将它们打印到控制台。

$ dotnet run
Mercury
Venus
Earth
Mars
Jupiter
Saturn
Uranus
Neptune

C# break 语句

break 语句可用于终止由 whileforswitch 语句定义的块。

Program.cs
var random = new Random();

while (true)
{
    int num = random.Next(1, 30);
    Console.Write("{0} ", num);

    if (num == 22)
    {
        break;
    }
}

Console.Write('\n');

我们定义一个无限 while 循环。我们使用 break 语句来退出此循环。我们选择一个介于 1 到 30 之间的随机值。我们打印该值。如果该值等于 22,我们将完成无限 while 循环。

$ dotnet run
18 3 21 26 12 27 23 25 2 21 15 4 18 12 24 13 7 19 10 26 5 22

C# continue 语句

continue 语句用于跳过循环的一部分并继续循环的下一次迭代。它可以与 forwhile 语句结合使用。

在以下示例中,我们打印一个无法被 2 整除而没有余数的数字列表(奇数)。

Program.cs
int num = 0;

while (num < 1000)
{
    num++;

    if (num % 2 == 0)
    {
        continue;
    }

    Console.Write($"{num} ");
}

Console.Write('\n');

我们使用 while 循环迭代数字 1..999。

if (num % 2 == 0)
{
    continue;
}

如果表达式 num % 2 返回 0,则可以被 2 整除。执行 continue 语句,并且跳过循环的其余部分。在我们的例子中,跳过循环的最后一个语句,并且该数字不会打印到控制台。开始下一次迭代。

来源

语句、表达式、运算符

在本文中,我们介绍了 C# 控制流程结构。

作者

我叫 Jan Bodnar,是一位充满热情的程序员,拥有丰富的编程经验。我从 2007 年开始撰写编程文章。到目前为止,我已经撰写了 1,400 多篇文章和 8 本电子书。我在编程教学方面拥有超过十年的经验。

列出所有 C# 教程