练习 - 使用 if 语句创建决策逻辑
大多数应用程序都包含大量执行路径。 例如,应用程序可以根据用户选择的菜单选项实现不同的执行路径。 开发人员将实现不同执行路径的代码称为代码分支。
运用最广泛的代码分支语句是 if
语句。 if
语句依赖布尔表达式,后者用一组括号括起来。 如果表达式为 true,则执行 if
语句后面的代码。 如果不是,.NET 运行时将忽略此代码且不会执行它。
在本练习中,你将通过创建一个游戏来练习编写 if
语句。 首先,你将定义游戏规则,然后使用代码将其实现。
你将使用 Random.Next()
方法来模拟抛掷三个六面骰子。 你将评估抛掷出的点数以计算得分。 如果得分大于任意总和,则向用户显示一条获胜消息。 如果得分小于任意总和,则向用户显示一条失败消息。
- 如果抛掷任何两个骰子得到相同的值,则因两个骰子投出同样的点数获得两点奖励得分。
- 如果抛掷全部三个骰子都得到相同的值,则因三个骰子投出同样的点数获得六点奖励得分。
- 如果三个骰子投出的点数之和加上所有奖励点数大于等于 15,则你赢得比赛。 否则,就是你输了。
你将在详细了解 if
语句的同时完善规则。
重要
本练习大量使用 System.Random
类。 如果需要复习 Random.Next()
的工作原理,可以参考标题为“使用 C# 从 .NET 类库调用方法”的 Microsoft Learn 模块。
准备编码环境
本模块包括指导你完成生成和运行示例代码的过程的活动。 建议使用 Visual Studio Code 作为开发环境来完成这些活动。 使用 Visual Studio Code 来完成这些活动将帮助你在供全球专业人员使用的开发人员环境中更舒适地编写和运行代码。
打开 Visual Studio Code。
可以使用 Windows“开始”菜单(或等效资源 [对于其他 OS])打开 Visual Studio Code。
在 Visual Studio Code 的“文件”菜单上,选择“打开文件夹”。
在“打开文件夹”对话框中,导航到 Windows“桌面”文件夹。
如果使用了其他文件夹位置来保存代码项目,可以改用该文件夹位置。 对于此训练,重要的是要有一个容易找到和记住的位置。
在“打开文件夹”对话框中,选择“选择文件夹”。
如果看到一个询问是否信任作者的安全对话框,请选择“是”。
在 Visual Studio Code 的“终端”菜单上,选择“新终端”。
请注意,“终端”面板中的命令提示符显示当前文件夹的文件夹路径。 例如:
C:\Users\someuser\Desktop>
注意
如果你在自己的电脑上工作,而不是在沙盒或托管环境中工作,并且你已经完成此 C# 系列中的其他 Microsoft Learn 模块,那么你可能已经为代码示例创建了一个项目文件夹。 如果是这种情况,可以跳过下一步,该步骤用于在 TestProject 文件夹中创建控制台应用。
在终端命令提示符处,若要在指定文件夹中新建控制台应用程序,请键入“dotnet new console -o ./CsharpProjects/TestProject”,然后按 Enter。
此 .NET CLI 命令使用 .NET 程序模板在指定文件夹位置创建新的 C# 控制台应用程序项目。 该命令会自动创建 CsharpProjects 和 TestProject 文件夹,并使用 TestProject 作为
.csproj
文件的名称。在“资源管理器”面板中,展开“CsharpProjects”文件夹。
你应会看到 TestProject 文件夹和两个文件,一个名为 Program.cs 的 C# 程序文件和一个名为 TestProject.csproj 的 C# 项目文件。
在“资源管理器”面板中,若要在“编辑器”面板中查看代码文件,请选择“Program.cs”。
删除现有代码行。
在本模块中,你将使用此 C# 控制台项目来创建、生成和运行代码示例。
关闭“终端”面板。
编写代码以生成三个随机数字并在输出中显示
确保在 Visual Studio Code 中打开了一个空的 Program.cs 文件。
若要为本练习创建初始代码,请输入以下内容:
Random dice = new Random(); int roll1 = dice.Next(1, 7); int roll2 = dice.Next(1, 7); int roll3 = dice.Next(1, 7); int total = roll1 + roll2 + roll3; Console.WriteLine($"Dice roll: {roll1} + {roll2} + {roll3} = {total}");
花点时间查看输入的代码。
首先,创建
System.Random
类的新实例,并将对该对象的引用存储在名为dice
的变量中。 然后,你会对dice
对象调用三次Random.Next()
方法,同时提供下限和上限,将可能的值限制在1
到6
之间(上限是排他性的)。 你会将这三个随机数字分别存储在变量roll1
、roll2
和roll3
中。接下来,你将三个骰子投出的点数相加,并将该值保存到名为
total
的整数变量中。最后,你会使用
WriteLine()
方法通过字符串内插显示三个值。运行代码时,应会看到以下消息(数字会有所不同)。
Dice roll: 4 + 5 + 2 = 11
第一个任务是设置任务。 现在,你可以将决策逻辑添加到代码中,使游戏更加有趣。
添加一个 if 语句,以基于 total 变量的值显示不同的消息
在 Visual Studio Code 编辑器中,将光标定位在代码文件的底部,然后创建一个空白代码行。
若要创建第一个游戏功能,请输入以下
if
语句。if (total > 14) { Console.WriteLine("You win!"); } if (total < 15) { Console.WriteLine("Sorry, you lose."); }
这两个
if
语句用于处理获胜和失败的场景。 花点时间检查第一个if
语句。请注意,
if
语句由三个部分组成:if
关键字- 用
()
括起来的布尔表达式 - 由大括号
{ }
定义的代码块
在运行时,会评估布尔表达式
total > 14
。 如果此语句为 true,即如果total
的值大于14
,则执行流程将执行代码块中定义的代码。 换言之,它会执行大括号中的代码。但是,如果布尔表达式为 false,即
total
的值小于14
,则执行流程会跳过该代码块。 换言之,它不会执行大括号中的代码。最后,第二个
if
语句控制表明用户是否失败的消息。 在下一单元,你将使用if
语句的变体来将这两个语句精简为一个语句,同时更明确地表达意图。
什么是布尔表达式?
布尔表达式是返回布尔值(true
或 false
)的任意代码。 最简单的布尔表达式就是值 true
和 false
。 此外,布尔表达式可以是返回值 true
或 false
的方法的结果。 例如,下面是一个简单的代码示例,它使用 string.Contains()
方法评估某个字符串是否包含另一个字符串。
string message = "The quick brown fox jumps over the lazy dog.";
bool result = message.Contains("dog");
Console.WriteLine(result);
if (message.Contains("fox"))
{
Console.WriteLine("What does the fox say?");
}
由于 message.Contains("fox")
返回 true
或 false
值,因此它符合作为布尔表达式的条件,可在 if
语句中使用。
其他简单的布尔表达式可通过使用运算符比较两个值进行创建。 运算符包括:
==
,用于测试是否相等的“等于运算符”>
,用于测试左边的值是否大于右边的值的“大于运算符”<
,用于测试左边的值是否小于右边的值的“小于运算符”>=
,“大于或等于运算符”<=
,“小于或等于运算符”- 等等
备注
Microsoft Learn 中的 C# 训练系列使用了一整个模块来介绍布尔表达式。 有很多运算符可用来构造布尔表达式,本模块将只介绍一些基础知识。 有关布尔表达式的详细信息,请参阅标题为“计算布尔表达式以使用 C# 做出决策”的 Microsoft Learn 模块。
在此示例中,你评估了布尔表达式 total > 14
。 但是,你本可选择布尔表达式 total >= 15
,因为这两者在此情况下是等效的。 鉴于游戏的规则规定“如果三个骰子投出的点数加上所有奖励得分大于等于 15,则你赢得游戏”,你可能应实现 >= 15
表达式。 你将在练习的下一步中进行此更改。
什么是代码块?
代码块是包含一行或多行代码的集合,其中代码行由左大括号和右大括号 { }
定义。 它表示在软件系统中用途单一的完整代码单位。 在此情况下,如果布尔表达式为 true,则会在运行时执行代码块中的所有代码行。 反之,如果布尔表达式为 false,则会忽略代码块中的所有代码行。
你还应该知道代码块可以包含其他代码块。 事实上,在应用程序中,一个代码块“嵌套”在另一个代码块中是很常见的。 在本模块的稍后部分,当你在一个 if
语句的代码块中创建另一个 if
语句时,你将开始嵌套你自己的代码块。
注意
Microsoft Learn 中的 C# 训练系列使用了一整个模块来介绍理解代码块。 代码块对于理解代码组织和结构至关重要,它们还定义了变量范围的边界。 请参阅模块 [Control variable scope and logic using code blocks in C#](TBD)
。
再添加一个 if 语句来实现双倍奖励
接下来,你将实现如下规则:“如果抛掷任何两个骰子得到相同的值,则因两个骰子投出同样的点数获得两点奖励得分”。 修改上述步骤中的代码以匹配以下代码清单:
在 Visual Studio Code 编辑器中,将光标定位在第一个
if
语句上方的空白代码行处。若要创建“双倍奖励”游戏功能,请输入以下
if
语句。if ((roll1 == roll2) || (roll2 == roll3) || (roll1 == roll3)) { Console.WriteLine("You rolled doubles! +2 bonus to total!"); total += 2; }
你在这里合并了三个布尔表达式,以便在单行代码中创建一个复合布尔表达式。 这有时被称为“复合条件”。 你有一组外括号,它包含由两个竖线分隔符分隔的三组内括号。
双竖线分隔符
||
是“逻辑或”运算符,主要表示“要使整个布尔表达式为 true,要么左侧表达式必须为 true,要么右侧表达式必须为 true”。 如果两个布尔表达式均为 false,则整个布尔表达式为 false。 你使用两个“逻辑或”运算符,以便可将评估扩展到第三个布尔表达式。首先,评估
(roll1 == roll2)
。 如果它为 true,则整个表达式为 true。 如果它为 false,则评估(roll2 == roll3)
。 如果它为 true,则整个表达式为 true。 如果它为 false,则评估(roll1 == roll3)
。 如果它为 true,则整个表达式为 true。 如果它为 false,则整个表达式为 false。如果复合布尔表达式为 true,则执行后面的代码块。 此时,有两行代码。 第一行代码会将消息打印发送给用户。 第二行代码将
total
的值增加2
。若要提高代码的可读性,请更新第二个
if
语句,如下所示:if (total >= 15)
请注意,你现在在表达式中使用的是
>=
运算符,该运算符用于评估获胜掷骰。>=
运算符表示“大于或等于”。 因此,你可以将total
与15
(而不是14
)的值进行比较。 通过这些更改,用于评估获胜掷骰的表达式现在类似于用于评估失败掷骰的表达式。 这应有助于使代码更易于理解(更具可读性)。 由于使用的是整数值,因此新表达式(total >= 15)
的功能与之前编写的(total > 14)
完全相同。花点时间查看你的代码。
你的代码应与以下内容一致:
Random dice = new Random(); int roll1 = dice.Next(1, 7); int roll2 = dice.Next(1, 7); int roll3 = dice.Next(1, 7); int total = roll1 + roll2 + roll3; Console.WriteLine($"Dice roll: {roll1} + {roll2} + {roll3} = {total}"); if ((roll1 == roll2) || (roll2 == roll3) || (roll1 == roll3)) { Console.WriteLine("You rolled doubles! +2 bonus to total!"); total += 2; } if (total >= 15) { Console.WriteLine("You win!"); } if (total < 15) { Console.WriteLine("Sorry, you lose."); }
请注意,用于评估获胜掷骰和失败掷骰的表达式之间的对齐方式已得到优化。
再添加一个 if 语句来实现三倍奖励
接下来,你将实现规则:“如果掷出的所有三个骰子的结果相同,则掷出三倍可获得六分奖励”。修改前面步骤中的代码以匹配以下代码清单:
在 Visual Studio Code 编辑器中,在“双倍奖励”
if
语句的代码块下方创建一个空白代码行。若要创建“三倍奖励”游戏功能,请输入以下
if
语句。if ((roll1 == roll2) && (roll2 == roll3)) { Console.WriteLine("You rolled triples! +6 bonus to total!"); total += 6; }
你在这里合并了两个布尔表达式,以便在单行代码中创建一个复合布尔表达式。 你有一组外括号,它包含由两个“与”字符分隔的两组内括号。
双与字符
&&
是“逻辑与”运算符,主要表示“只有当两个表达式均为 true 时,整个表达式才为 true”。 在此情况下,如果roll1
等于roll2
,并且roll2
等于roll3
,那么通过推断,roll1
必须等于roll3
且用户投出了三倍奖励分数。在 Visual Studio Code 的“文件”菜单上,单击“保存”。
花点时间查看你的代码。
确保代码与以下示例匹配:
Random dice = new Random(); int roll1 = dice.Next(1, 7); int roll2 = dice.Next(1, 7); int roll3 = dice.Next(1, 7); int total = roll1 + roll2 + roll3; Console.WriteLine($"Dice roll: {roll1} + {roll2} + {roll3} = {total}"); if ((roll1 == roll2) || (roll2 == roll3) || (roll1 == roll3)) { Console.WriteLine("You rolled doubles! +2 bonus to total!"); total += 2; } if ((roll1 == roll2) && (roll2 == roll3)) { Console.WriteLine("You rolled triples! +6 bonus to total!"); total += 6; } if (total >= 15) { Console.WriteLine("You win!"); } if (total < 15) { Console.WriteLine("Sorry, you lose."); }
在“资源管理器”面板中,若要在 TestProject 文件夹位置打开终端,请右键单击“TestProject”,然后选择“在集成终端中打开”。
终端面板应打开,并应包含一个命令提示符,显示终端已打开转到 TestProject 文件夹位置。
在终端命令提示符处,若要运行代码,请键入 dotnet run,然后按 Enter。
注意
如果看到一条指示“找不到要运行的项目”的消息,请确保终端命令提示符显示预期的 TestProject 文件夹位置。 例如:
C:\Users\someuser\Desktop\csharpprojects\TestProject>
你应看到类似于以下结果之一的输出:
Dice roll: 3 + 6 + 1 = 10 Sorry, you lose.
或如下内容:
Dice roll: 1 + 4 + 4 = 9 You rolled doubles! +2 bonus to total! Sorry, you lose.
或如下内容:
Dice roll: 5 + 6 + 4 = 15 You win!
如果足够幸运,则会看到如下内容:
Dice roll: 6 + 6 + 6 = 18 You rolled doubles! +2 bonus to total! You rolled triples! +6 bonus to total! You win!
但是等一下,你真的应该让玩家同时获得三倍奖励分数和双倍奖励分数吗? 毕竟,三个骰子投出相同的点数表示他们两个骰子也投出了相同的点数。 理想情况下,奖励不应叠加。 应该有两个单独的奖励条件。 这是一个逻辑 bug,需要进行更正。
逻辑上的问题以及优化代码的机会
虽然这是一个好的开始,而且你也学到了许多关于 if
语句、布尔表达式、代码块、“逻辑或”和“逻辑与”运算符等等的知识,但仍然有很多可优化的地方。 你将在下一单元中执行此操作。
回顾
- 使用
if
语句对代码逻辑进行分支。 如果if
决策语句的布尔表达式等于 true,它将执行其代码块中的代码。 否则,运行时会跳过代码块并转到代码块后面的下一行代码。 - 布尔表达式是返回布尔值的任何表达式。
- 布尔运算符会比较其两侧的值是否相等,进行比较等操作。
- 代码块由大括号
{ }
进行定义。 它会收集应被视为单个单元的代码行。 - “逻辑与”运算符
&&
聚合两个表达式,这两个子表达式都必须为 true,才能使整个表达式为 true。 - “逻辑或”运算符
||
聚合两个表达式,如果其中一个子表达式为 true,则整个表达式为 true。