首页 > 解决方案 > C# 行程申请 - 在继续之前重复查询

问题描述

我一直在尝试重构一个 C# 控制台应用程序,该应用程序询问用户想去哪里旅行、记录位置、重复问题,然后询问另一个位置或打印用户指定的位置(结束程序)。

鉴于代码中的注释说明,我似乎已经准备好了一切。但是,在 ContinuePlanning() 方法中,无论用户响应如何,它都会在继续程序之前重复第二次,我无法弄清楚原因。

据我所知,逻辑是有道理的,但我知道我在代码的某个地方遗漏了一个简单的步骤。谁能提供一些关于为什么会发生这种情况的见解?

程序.cs

using System;
using System.Collections.Generic;

// Synopsis: Everyone loves a great vacation! This application helps you keep track of all the wonderful places on your bucket list.

namespace TravelPlanner
{
    class Program
    {
        static void Main(string[] args)
        {

            // Display header
            Console.WriteLine("");
            Console.WriteLine("========================================");
            Console.WriteLine(" TRAVEL PLANNER ");
            Console.WriteLine("========================================");
            Console.WriteLine("");
            Console.WriteLine("Helping you keep track of the places you will travel. \r\n");

            /*
            3. PLAN ITINERARY
            -------------------------
            [ After completing steps #1 and #2, lets take the optimization even further...
              Reviewing what you've accomplished, you will notice that each step now contains a single line
              of code. We've compartmentalized each action into a method, excellent refactoring!

              The while loop below contains these two actions. Looping over those actions is how we plan the
              itinerary. So lets migrate the loop and the nested actions into the middle of the Plan() method.
              The only thing left now is the creation of the list. Add one line that sets the value of
              "locations" to the calling of that method. Planning the itinerary has now be accomplished with
              one line within Main()!

              The Main() method has become an outline of the application... after displaying the header, we Plan(),
              then display what we've planned, and finally display a footer.

              Uh, oh... don't forget the syntax problem!
            ] */

                // Create List
                List<string> locations = new List<string>();

                // Repeat until all locations are added
                bool planning = true;
                while (planning)
                {

                    /*
                    1. GET LOCATION
                    -------------------------
                    [ Migrate the following, except for the last line, into the Itinerary class' (Itinerary.cs)
                      GetLocation() method. Then change the last line so "location," within locations.Add()
                      calls that GetLocation() method. Refer to the lesson on static classes/methods to see
                      how you can call methods from other classes.

                      Also, make sure to fix the validation's logic errors!
                    ] */

                    locations.Add(Itinerary.GetLocation());

                    /*
                    2. CONTINUE PLANNING
                    -------------------------
                    [ Migrate all of the following into the ContinuePlanning() method. Replace this with a
                      single line that sets the value of the "planning" variable to the returned value.

                      This validation also contains a logic error!
                    ] */

                    planning = Itinerary.ContinuePlanning(planning);

                }

            /*
            4. DISPLAY ITINERARY
               -------------------------
                [ The Itinerary class has allowed us to organize the code, containing all the methods (processes)
                  related to the planning of the itinerary: Plan(), GetLocation(), and ContinuePlanning().
                  Since the following code is used to display the itinerary, it should be there too.
                  
                  Migrate the following into the Display() method. Then replace with a call to that method.
                  Of course you'll need an argument for the "locations" list to display.

                  Carefully read the output to spot a syntax error... we want to practice string interpolation!
                ] */


            Itinerary.Display(locations);

            // -------------------------


            // Display footer
            Console.WriteLine("");
            Console.WriteLine("========================================");
            Console.WriteLine("Safe travels on your future trips!");
            Console.WriteLine("");
            Console.ReadKey();
        }   

    // End class
    }
}

行程.cs

using System;
using System.Collections.Generic;

// Synopsis: Collection of methods used in the planning and displaying of travel itinerary locations.

namespace TravelPlanner
{
    public class Itinerary
    {

        // Plan itinerary
        public static List<string> Plan()
        {

            // Create list for locations
            List<string> locations = new List<string>();

            return locations;
        }


        // Request location from user
        public static string GetLocation()
        {
            // Initial request
            Console.WriteLine("");
            Console.WriteLine("--------------------");
            Console.Write("Where would you like to travel? ");
            string location = Console.ReadLine();

            // Validate user input 
            while (String.IsNullOrWhiteSpace(location))
            {
                // Reminder not to leave blank
                Console.WriteLine("Please do not leave this blank! \r\n");

                // Ask again where they would like to go
                Console.Write("Where would you like to travel? ");

                // String for user input
                string newlocation = Console.ReadLine();
            }

            return location;
        }


        // Question - another location?
        public static bool ContinuePlanning(bool planning)
        {
            // Another location?
            Console.Write("Another location? (yes/no) ");
            string response = Console.ReadLine();

            // Validate user input
            if (response.ToLower() != "yes" || response.ToLower() != "no")
            {
                // Error message
                Console.WriteLine("Please only enter yes or no.");

                // Re-ask question
                Console.Write("Another location? (yes/no) ");
                response = Console.ReadLine();
            }

            // Continue planning?
            if (response.ToLower() == "no")
            {
                planning = false;
            }

            return planning;
        }

 
        // Display itinerary locations
        public static void Display(List<string> locations)
        {
            //Output the number of locations the user will visit
            Console.WriteLine("");
            Console.WriteLine("--------------------");
            Console.WriteLine($" You will take {locations.Count} trip(s).");

            //Output each location the user will visit
            for (int i = 0; i < locations.Count; i++)
            {
                Console.WriteLine($" You will visit {locations[i]}.");
            }
        }


    // End class
    }
}

提前致谢!

标签: c#console-application

解决方案


“据我所知,逻辑是有道理的”

这可能是因为您正在阅读它,因为有人可能会用英语说它,而不是作为逻辑代码语句。

  • 在英语中,我们会说,“如果他们没有回答“是”“否”,那么再问他们一次。
  • 在代码中,我们用不同的方式表达它:“如果答案不是“是”并且答案不是“否”,那么再问他们一次”

原因如下:

  • 如果任一操作数是,则条件逻辑 OR 运算符( ||) 将返回(并且评估将在第一个结果处停止): truetruetrue
    • false || false == false
    • false || true == true
    • true || false == true
    • true || true == true
  • 这与条件逻辑 AND 运算符( &&) 不同,后者true仅在两个操作数都为真时才返回。
    • false && false == false
    • false && true == false
    • true && false == false
    • true && true == true

现在让我们看看你的if情况ContinuePlanning

if (response.ToLower() != "yes" || response.ToLower() != "no")

现在,如果有人进入"yes",第一部分是false,第二部分是true,所以条件将评估为true。同样,如果他们输入"no"(或任何其他输入),第一部分是true,因此条件将评估为true

相反,我们要测试第一部分和第二部分是否为真,所以我们应该使用&&运算符:

if (response.ToLower() != "yes" && response.ToLower() != "no")

现在如果他们输入"yes"or "no",那么只有那些操作数是true,所以条件将评估为false。如果他们输入任何其他输入,那么两个条件都是true,这就是我们正在寻找的。


另一个问题是这个方法接受一个参数,如果用户输入了bool,修改它,然后返回它。这样做的问题是,如果变量开始是,那么无论用户输入什么我们都会返回。此外,此方法不需要来自调用者的任何参数。我们应该只在本地声明变量。false"no"falsefalse

如果他们输入"yes"or "no",我们也只检查一次,但我们应该循环执行,以防他们真的是笨拙的打字员。:)

// Question - another location?
public static bool ContinuePlanning()
{
    // Start out assuming we will contiune planning
    bool continuePlanning = true;

    // Another location?
    Console.Write("Another location? (yes/no) ");

    // Get the user reponse and make it lower case
    string response = Console.ReadLine().ToLower();

    // Validate user input
    while (response != "yes" && response != "no")
    {
        // Error message
        Console.WriteLine("Please only enter yes or no.");

        // Re-ask question
        Console.Write("Another location? (yes/no) ");
        response = Console.ReadLine();
    }

    // If the user doesn't want to continue, set our variable
    if (response == "no") continuePlanning = false;

    return continuePlanning;
}

推荐阅读