练习 - 生成示例数据和菜单选择循环

已完成

在本练习中,你将查看 Starter 项目中的代码,执行一些代码清理任务,然后开始向应用程序添加功能。 在本练习中完成的任务如下:

  1. 代码评审:评审 Program.cs 文件的内容。
  2. 示例数据:将 if-elseif-else 结构转换为可提高可读性的 switch-case 结构。
  3. 菜单循环:将主菜单和菜单项选择放在循环中反复执行,直到用户输入“退出”。
  4. 菜单选择:编写 switch-case 结构的代码,该结构为每个菜单选项建立单独的代码分支。
  5. 代码分支:在菜单项分支中编写占位符,以便在应用功能开发前向用户提供反馈。
  6. 验证测试:对在本练习中开发的代码执行验证测试。

查看 Program.cs 文件的内容

在此任务中,你将完成对 Starter 项目代码的逐步讲解。 Program.cs文件包含在此模块期间更新的应用程序的初步版本。 现有代码为应用程序生成示例数据,并显示菜单选项列表。 菜单选项表示应用程序的主要功能。

  1. 确保 GuidedProject 文件夹在 Visual Studio Code 中处于打开状态。

    上一单元包含一个“设置”部分,描述如何打开初学者项目。 如有必要,请返回并按照设置说明进行操作。

  2. “资源管理器” 视图中,展开 “初学者 ”文件夹,然后选择 Program.cs

    选择Program.cs文件时,文件内容在 Visual Studio Code 编辑器中打开。

    如果“资源管理器”视图未打开,请从 Visual Studio Code 活动栏中选择“资源管理器”。 “资源管理器”按钮位于活动栏顶部。

  3. 请花几分钟时间查看 Program.cs 文件中的代码。

  4. 请注意,代码的顶部部分以一些变量声明开头。

    // the ourAnimals array will store the following: 
    string animalSpecies = "";
    string animalID = "";
    string animalAge = "";
    string animalPhysicalDescription = "";
    string animalPersonalityDescription = "";
    string animalNickname = "";
    
    // variables that support data entry
    int maxPets = 8;
    string? readResult;
    string menuSelection = "";
    
    // array used to store runtime data, there is no persisted data
    string[,] ourAnimals = new string[maxPets, 6];
    

    在文件的顶部,会看到注释行和变量列表。 这些变量,从 animalSpeciesanimalNickname,用于保存宠物特征的值。 稍后在代码中,将特征值分配给名为 ourAnimals多维字符串数组。 其中每个变量都初始化为包含零长度字符串 ""ourAnimals 数组在代码中稍远一点的位置声明。

    下一组变量是混合 string 变量和 int 变量,用于生成示例数据、读取用户输入并为主程序循环建立退出条件。 你可能已注意到代码行 string? readResult;。 在如下所示的变量声明中使用时, ? 字符定义可为 null 的类型变量。 使用 Console.ReadLine() 该方法读取用户输入的值时,最好使用可为 null 的类型。

    最后一个变量是一个名为 ourAnimals的二维字符串数组。 由于实例化数组而不初始化任何值,因此使用 new 运算符( new 该运算符用于创建类型的新实例)。 行数由 maxPets 定义,该项已初始化为 8。 您要存储的特征数量为6,即您在上面检查的字符串变量。

  5. 向下滚动以查看包含 for 选择构造的 if-elseif-else 循环。

    注释

    如果在 switch 循环的代码块中看到 if-elseif-else 语句而不是 for,请确保查看 Starter 文件夹中的 Program.cs 文件,而不是 Final 文件夹中的 Program.cs 文件。 你不希望对“最终”文件夹中的代码进行更改。 可能需要在本模块的后面部分使用最终文件夹作为参考。

  6. 请注意, for 循环使用 maxPets 变量在迭代数上建立上限。

  7. 请注意,构造 if-elseif-else 会根据宠物特征选择性地对代码进行分支。

    if-elseif-else 构造用于为循环的前四个迭代 for 定义不同的值。 第四次迭代后,所有特征都分配有一个空或零长度的字符串。

    动物特征变量的值在 for 循环的底部被分配给 ourAnimals 数组。

  8. 滚动到代码文件的底部,然后检查用于显示菜单选项并读取用户选择的代码。

  9. 请注意,将方法返回 Console.ReadLine() 的值分配给可为 null 的字符串 readResult

    使用可为 null 的字符串是从 ReadLine() 方法捕获输入的最佳做法。 验证输入值是否不为 null 后,将该值分配给名为 menuSelection的标准字符串变量。 此过程使你能够评估菜单选择值,而不必担心 null 值。 如果字符串被传递为 null 值,则接受字符串作为输入参数的许多方法都会生成错误。 如果不遵循此输入模式,则生成项目时,代码编译器可能会生成警告。

    Program.cs文件的最后几行会显示菜单选项的选择,然后暂停执行,直到按下 Enter 键。

将 if 语句转换为 switch 语句

在此任务中,将现有 if-elseif-else 构造转换为构造 switch-case 。 语句 switch 可提高代码的可读性。

  1. 向上滚动到用于生成示例数据的 for 循环的开头。

  2. 请注意,构造 if-elseif-else 以以下 if 语句和代码块开头:

    if (i == 0)
    {
        animalSpecies = "dog";
        animalID = "d1";
        animalAge = "2";
        animalPhysicalDescription = "medium sized cream colored female golden retriever weighing about 65 pounds. housebroken.";
        animalPersonalityDescription = "loves to have her belly rubbed and likes to chase her tail. gives lots of kisses.";
        animalNickname = "lola";
    }
    
  3. 将初始 if 语句和代码块替换为以下代码:

    switch (i)
    {
        case 0:
            animalSpecies = "dog";
            animalID = "d1";
            animalAge = "2";
            animalPhysicalDescription = "medium sized cream colored female golden retriever weighing about 65 pounds. housebroken.";
            animalPersonalityDescription = "loves to have her belly rubbed and likes to chase her tail. gives lots of kisses.";
            animalNickname = "lola";
            break;
    
    

    case 0: 代码执行与它所替换的 if (i == 0) 选择相同的操作。 你将进行相应的替换,以完成从 if-elseif-else 构造到 switch-case 构造的转换。

  4. 请注意,现在 ; 语句末尾的 break 下会显示一个红色波浪线符号。

    Visual Studio Code 使用红色波浪线来帮助发现代码中的问题。 在这种情况下,存在一些问题。 首先,您尚未关闭 switch 语句的代码块。 此外,你的一个 else if 没有 if,这是不允许的。 在完成从ifswitch的转换时,你可以修复每个问题。

  5. else if (i == 1) 语句和代码块替换为以下代码:

    case 1:
        animalSpecies = "dog";
        animalID = "d2";
        animalAge = "9";
        animalPhysicalDescription = "large reddish-brown male golden retriever weighing about 85 pounds. housebroken.";
        animalPersonalityDescription = "loves to have his ears rubbed when he greets you at the door, or at any time! loves to lean-in and give doggy hugs.";
        animalNickname = "loki";
        break;
    
    
  6. else if (i == 2) 语句和代码块替换为以下代码:

    case 2:
        animalSpecies = "cat";
        animalID = "c3";
        animalAge = "1";
        animalPhysicalDescription = "small white female weighing about 8 pounds. litter box trained.";
        animalPersonalityDescription = "friendly";
        animalNickname = "Puss";
        break;
    
    
  7. else if (i == 3) 语句和代码块替换为以下代码:

    case 3:
        animalSpecies = "cat";
        animalID = "c4";
        animalAge = "?";
        animalPhysicalDescription = "";
        animalPersonalityDescription = "";
        animalNickname = "";
        break;
    
    
  8. else 语句和代码块替换为以下代码:

    default:
        animalSpecies = "";
        animalID = "";
        animalAge = "";
        animalPhysicalDescription = "";
        animalPersonalityDescription = "";
        animalNickname = "";
        break;
    
    }
    
  9. 请注意,构造 if-elseif-else 现在完全被构造 switch-case 替换,红色波浪线符号消失。

    如果构造的某些 if-elseif-else 部分仍保留,或者 switch 语句不完整,请检查是否错过了步骤。

  10. 已完成 switch-case 的构造应具有类似于以下代码的结构:

    注释

    用于分配宠物特征值的变量已从下面的代码示例中删除,以缩短代码行数。 代码应包括每个case模式的字符串变量赋值,包括默认情况。

    switch (i)
    {
        case 0:
            // variable assignments were removed for this view of the structure
            break;
    
        case 1:
            // variable assignments were removed for this view of the structure
            break;
    
        case 2:
            // variable assignments were removed for this view of the structure
            break;
    
        case 3:
            // variable assignments were removed for this view of the structure
            break;
    
        default:
            // variable assignments were removed for this view of the structure
            break;
    }
    

    回想一下,执行一个 switch 部分不能“贯穿”执行到下一个 switch 部分。 break 语句用于确保不会发生“贯穿”。

  11. 在 Visual Studio Code 的“文件”菜单上,选择“保存”。

  12. 在“EXPLORER”视图中,右键单击“Starter”,然后选择“在集成终端中打开”。

    终端面板应会在代码编辑器区域下方打开。

    可通过多种方式打开 Visual Studio Code 的集成终端。 例如,顶部菜单提供从“视图”菜单和“终端”菜单对终端面板的访问。 还可以了解用于打开终端面板的键盘快捷方式。 每种方法都是可接受的。

  13. 请注意,终端面板包含命令行提示符,并且提示符显示当前文件夹路径。

    例如:

    C:\Users\someuser\Desktop\GuidedProject\Starter>
    

    可以使用终端面板运行命令行接口 (CLI) 命令,例如 dotnet builddotnet rundotnet build 命令将编译代码,并显示与代码语法相关的错误和警告消息。

    重要

    需要确保终端命令提示符对项目工作区的根目录打开。 在本例中,项目工作区的根目录是 Starter 文件夹,Starter.csproj 和 Program.cs 文件位于该文件夹中。 在终端中运行命令时,这些命令将使用当前文件夹位置执行作。 如果从不包含文件的文件夹位置运行 dotnet builddotnet run 命令,该命令将生成错误消息。

  14. 在终端命令提示符处,若要生成项目代码,请输入以下命令:dotnet build

    几秒钟后,应会看到一条消息,指出生成成功,有 0 个警告,0 个错误。

    Determining projects to restore...
    All projects are up-to-date for restore.
    Starter -> C:\Users\someuser\Desktop\GuidedProject\Starter\bin\Debug\net6.0\Starter.dll
    
    Build succeeded.
        0 Warning(s)
        0 Error(s)
    
  15. 如果看到“错误”或“警告”消息,需要先修复它们,然后再继续。

    “错误”和“警告”消息列出了可在其中找到问题的代码行。 以下消息是 Build FAILED 错误消息的示例:

    C:\Users\someuser\Desktop\GuidedProject\Starter\Program.cs(53,18): error CS1002: ; expected [C:\Users\someuser\Desktop\GuidedProject\Starter\Starter.csproj]

    此消息告知检测到的错误类型以及查找位置。 在本例中,消息告知 Program.cs 文件包含错误 - error CS1002: ; expected; expected 表明你忘记了在语句末尾处包含 ;。 消息的 Program.cs(53,18) 部分告知,错误位于代码行 53 上左侧 18 个字符处。

    这样的语法错误会阻止您的 Build 成功(生成失败)。 某些生成消息提供“警告”而不是“错误”,这意味着有一些需要关注的问题,但你可以尝试运行程序(生成成功)。

    修复问题并保存更新后,即可再次运行 dotnet build 命令。 继续运行,直到出现 0 个警告和 0 个错误。

    注释

    如果您自行解决问题时遇到困难,可以检查 Final 文件夹中的 Program.cs 代码,该代码是您在安装过程中完成的下载的一部分。 “最终”文件夹中Program.cs代码表示本模块中所有练习的结论,因此它将包含尚未创建的代码。 它看起来可能与你在此点在 Guided 项目中开发的Program.cs代码大相径庭。 但是,可以尝试在 Final 中检查Program.cs代码,以帮助隔离和修复代码中的问题。 请避免在最终文件夹中使用代码作为指南。 请记住,开发人员从错误中吸取教训,并且每个开发人员都会花时间查找和修复错误。

  16. 关闭“终端”面板。

创建程序菜单循环

在此任务中,你将生成一个 do 循环,其中包含菜单选项和读取用户输入的代码。 此循环可确保每次用户进行菜单选择时,都会刷新主菜单。 循环将持续执行,直到用户选择退出程序。

  1. 在 Visual Studio Code 编辑器中,在用于显示菜单选项的代码顶部,找到以下注释:

    // display the top-level menu options
    
  2. 在注释上方创建一个空白代码行,然后输入以下代码:

    do
    {
    
    

    通过将程序的菜单选项包含在循环 do 中,可确保用户至少看到一次菜单选项。

  3. 向下滚动到代码文件的底部。

  4. 在暂停代码执行的代码下方创建一个空白代码行,然后按如下所示更新代码:

    // pause code execution
    readResult = Console.ReadLine();
    
    } while ();
    

    请注意,你已经关闭了 do 循环的代码块,并且已开始构造 while 语句。

  5. 若要按如下所示指定由 while 语句计算的布尔表达式,请更新 while 语句:

    while (menuSelection != "exit");
    

    此表达式将确保 do 循环循环访问,直到用户选择“退出”应用程序。 每次迭代都会显示菜单并读取用户的菜单选择。

  6. 请注意,不会在 do 循环的代码块中看到代码行缩进。

  7. 若要让 Visual Studio Code“修复”代码行的缩进,请在代码编辑器中右键单击,然后选择“ 设置文档格式”。

    除了正确缩进代码行之外, “格式文档 ”命令还将应用其他代码格式规则。 但是,它不会修复代码中的语法错误,如果代码包含不完整或格式不正确的代码块,则可能会产生意外结果。 只要你谨慎使用,“设置文档格式”命令就很有用

    调用此命令的键盘快捷方式包括:

    • 在 Windows 上按 Shift + Alt + F
    • 在 Mac 上按 Shift + Option + F
    • 在 Linux Ctrl + Shift + I 上

    也可以使用命令面板找到此命令。 若要从命令面板查找“格式文档”命令,请执行以下作:

    • “视图 ”菜单上,选择 “命令面板”,然后在提示符下输入 格式 D
    • 筛选的命令列表将显示 “设置文档格式 ”作为可选命令
  8. 在 Visual Studio Code 的“文件”菜单上,选择“保存”。

  9. 打开集成终端面板。

    可以通过右键单击 EXPLORER 中的 “初学者 ”文件夹,然后选择“ 在集成终端中打开”,打开终端面板。

  10. 在终端命令提示符处,输入 dotnet build 用于生成更新代码的命令。

    应会看到一条消息,报告 0 个警告和 0 个错误

  11. 请在继续操作之前修复报告的生成错误或警告。

  12. 在终端命令提示符处,输入 dotnet run 用于运行更新代码的命令。

    应用程序将开始运行。

  13. 验证主菜单选项是否按预期显示在终端面板中。

    应会在终端面板中看到以下内容。

    Welcome to the Contoso PetFriends app. Your main menu options are:
    1. List all of our current pet information
    2. Add a new animal friend to the ourAnimals array
    3. Ensure animal ages and physical descriptions are complete
    4. Ensure animal nicknames and personality descriptions are complete
    5. Edit an animal's age
    6. Edit an animal's personality description
    7. Display all cats with a specified characteristic
    8. Display all dogs with a specified characteristic
    
    Enter your selection number (or type Exit to exit the program)
    
  14. 在终端命令提示符下,若要选择菜单选项 1,请输入 1

    如果应用已暂停,光标位于“1”右侧,请按 Enter。 若要输入值,需要在键入 1 个字符后按 Enter 键。

  15. 验证代码是否回显输入的菜单选择。

    应会看到终端中显示的以下输出。

    You selected menu option 1.
    Press the Enter key to continue
    

    如果未看到此消息,请确保在运行 dotnet build 命令之前保存代码更新。 如果需要,请保存代码,然后再次尝试运行应用程序。

  16. 在终端命令提示符处,按 Enter 键继续。

    按 Enter 使代码可以继续执行,超过 Console.ReadLine() 方法,该方法位于应用程序结束时计算的 while 表达式之前。

  17. 若要验证代码是否继续接受其他菜单选择,请尝试输入一个或多个其他菜单项编号。

    如果代码在输入“1”后停止运行,请确保保存代码更新。 如果需要,请保存代码,然后再次尝试运行应用程序。

    你可能会注意到,你可以输入任何文本或数值,甚至输入字母和数字的组合。 开发管理用户输入的代码时,你将解决此问题。

  18. 在终端命令提示符处,若要验证正确评估循环的退出条件,请输入 Exitexit

    输入“Exit”或“exit”时,while 表达式的计算结果应为 false,代码执行应结束。

    重要

    如果在输入“exit”时代码执行未按预期停止,则可以在集成终端中按 Ctrl-C 强制代码执行停止。

  19. 关闭“终端”面板。

为菜单选择编写 switch 语句

在此任务中,你将为 switch 语句编写代码,该语句根据分配给 menuSelection 的值为代码执行创建分支。 您为每个菜单项编号创建一个 switch 标签。 创建单独的 switch 标签可确保单独管理每个菜单项。 语句 switch 可以很好地实现应用程序的预期逻辑。

  1. 在 Visual Studio Code 编辑器中,找到用于回显菜单选择的以下 Console.WriteLine() 代码行。

    Console.WriteLine($"You selected menu option {menuSelection}.");
    
  2. 若要开始开发 switch 语句,请按如下所示更新代码:

    //Console.WriteLine($"You selected menu option {menuSelection}.");
    //Console.WriteLine("Press the Enter key to continue");
    
    // pause code execution
    //readResult = Console.ReadLine();
    
    switch(menuSelection)
    {
    
    }
    
    
  3. 若要将第一个 case 模式添加到 switch 语句,请按如下所示更新 switch 语句代码:

    switch(menuSelection)
    {
        case "1":
            break;
    
    }
    

    你可能已经注意到,此处使用的事例模式看起来与在应用程序早期生成示例数据时使用的事例模式略有不同(case 1:case "1":)。 解释很简单。 你以前正在检查整数值,现在正在检查字符串值。

  4. 若要在你的switch-case构造中为每个剩余菜单选择编号创建选择分支,请按如下方式添加额外的case选项:

    switch(menuSelection)
    {
        case "1":
            break;
    
        case "2":
            break;
    
        case "3":
            break;
    
        case "4":
            break;
    
        case "5":
            break;
    
        case "6":
            break;
    
        case "7":
            break;
    
        case "8":
            break;
    
    }
    
  5. 请注意,可以将可选 default 情况添加到所选列表末尾,如下所示:

    switch(menuSelection)
    {
        // case selections 1-7 have been removed to simplify this sample code 
    
        case "8":
            break;
    
        default:
            break;
    }
    
  6. 在 Visual Studio Code 的“文件”菜单上,选择“保存”。

  7. 打开集成终端面板,然后运行命令以生成程序。

    使用dotnet build命令生成您的更新代码。

    您应该看到显示 0 个警告和 0 个错误的消息。

  8. 请在继续操作之前修复报告的生成错误或警告。

  9. 关闭“终端”面板。

为 switch 语句的每种情况编写占位符代码

在此任务中,你需要更新由你的 switch 语句创建的代码执行路径。 完成后,每个 switch 部分将向确认其菜单选择的用户提供反馈。 提供确认用户输入的反馈尤为重要,因为在此模块期间无法完成所有菜单选项的代码。 反馈允许用户知道代码识别了其输入,即使应用程序无法处理请求。

  1. 在 Visual Studio Code 编辑器中,找到包含 case "1": 所选内容的代码行:

    switch (menuSelection)
    {
        case "1":
            break;
    
    
  2. 若要在case "1":break;代码行之间向用户提供反馈信息,请按如下所示更新代码:

    switch (menuSelection)
    {
        case "1":
            // List all of our current pet information
            Console.WriteLine("this app feature is coming soon - please check back to see progress.");
            Console.WriteLine("Press the Enter key to continue.");
            readResult = Console.ReadLine();
            break;
    
    
  3. case "2": 所选内容添加相同的反馈消息,如下所示:

    switch (menuSelection)
    {
        case "1":
            // List all of our current pet information
            Console.WriteLine("this app feature is coming soon - please check back to see progress.");
            Console.WriteLine("Press the Enter key to continue.");
            readResult = Console.ReadLine();
            break;
    
        case "2":
            // List all of our current pet information
            Console.WriteLine("this app feature is coming soon - please check back to see progress.");
            Console.WriteLine("Press the Enter key to continue.");
            readResult = Console.ReadLine();
            break;
    
    
  4. case "2":选择的行注释更新为如下所示以反映第二个菜单选项:

    case "2":
        // Add a new animal friend to the ourAnimals array
        Console.WriteLine("this app feature is coming soon - please check back to see progress.");
        Console.WriteLine("Press the Enter key to continue.");
        readResult = Console.ReadLine();
        break;
    
    
  5. 对于 case "3":case "8": 选择,请使用反映关联的菜单项文本的行注释更新代码。

    例如,在 // Ensure animal ages and physical descriptions are complete 下方添加 case "3":

    可以从显示菜单选项的代码行复制菜单项文本。

    注释

    可以使用“设置文档格式”命令来清理格式。 这可能会加快工作速度,并为你提供更多时间来专注于你输入的代码,而不是它的外观。

  6. 对于 case "3":case "4": 选择,请在行注释下方添加以下反馈消息和 ReadLine ():

    Console.WriteLine("Challenge Project - please check back soon to see progress.");
    Console.WriteLine("Press the Enter key to continue.");
    readResult = Console.ReadLine();
    
  7. 对于其余 case 选择,请使用以下反馈消息和 ReadLine () 更新代码:

    Console.WriteLine("UNDER CONSTRUCTION - please check back next month to see progress.");
    Console.WriteLine("Press the Enter key to continue.");
    readResult = Console.ReadLine();
    

    注释

    如果将可选 default 案例添加到选择列表中,请不要向该案例添加反馈消息。

  8. 在 Visual Studio Code 的“文件”菜单上,选择“保存”。

    回想一下,如果在代码编辑器中右键单击,然后从上下文菜单中选择 “设置文档格式 ”,Visual Studio Code 将设置代码的格式。

  9. 打开“集成终端”面板,然后运行命令以生成程序。

    使用dotnet build命令生成您的更新代码。

  10. 请在继续操作之前修复报告的生成错误或警告。

检查你的工作

在此任务中,你将从集成终端运行应用程序,并验证 switch 语句是否按预期对代码进行分支。 此外,您还需验证每个菜单选择是否显示了预期的反馈信息。 主菜单循环的退出条件也将重新测试。

  1. 如有必要,打开 Visual Studio Code 的集成终端面板。

  2. 在终端命令提示符处,输入 dotnet run

  3. 在终端命令提示符下,若要选择第一个菜单选项,请输入 1

  4. 验证是否显示预期的“即将推出”消息。

  5. 重复上一步,输入其他每个菜单选项编号,以验证每个案例中是否显示预期的消息。

  6. 在终端命令提示符处,输入“Exit”或“exit”,验证是否仍正确评估退出条件

    重要

    如果代码执行未按预期停止,可以在集成终端中按 Ctrl-C 强制执行停止。

  7. 关闭“终端”面板。