【问题标题】:How to avoid repeating a similar code several times?如何避免多次重复类似的代码?
【发布时间】:2018-07-17 03:29:23
【问题描述】:

我正在做一个类似控制台应用程序的地铁餐厅。它在很大程度上依赖于循环,并且有一种特定类型的循环我已经重复了很多次。

基本上,我会编写选项,然后将光标放在初始选项上。用户在光标悬停时按 Enter 的任何选项都是选中的选项。

这是代码的第一部分(它有点大,但这就是我在这里问的原因):

static int Row = 0; //To set the row of the cursor

    static void Menu()
    {
        Console.WriteLine("Hi, welcome to Subway!"); //Line 0
        Console.WriteLine(); //Line 1

        //Bread Selection
        string[] breadOptions =
        {
                        "Hearty Italian",       //Element 0
                        "9-Grain Honey Oat",    //Element 1
                        "Jalapeno Cheese",      //Element 2
                        "Monterey Cheddar",     //Element 3
                        "Parmesan Oregano",     //Element 4
                        "Roasted Garlic",       //Element 5
                        "Rosemary & Sea Salt",  //Element 6
                        "Rye Bread",            //Element 7
                        "Gluten-Free Bread",    //Element 8
        };

        Console.WriteLine("Choose you bread!"); //Line 2
        Console.WriteLine("[ ]" + breadOptions[0]); //Line 3
        Console.WriteLine("[ ]" + breadOptions[1]); //Line 4
        Console.WriteLine("[ ]" + breadOptions[2]); //Line 5
        Console.WriteLine("[ ]" + breadOptions[3]); //Line 6
        Console.WriteLine("[ ]" + breadOptions[4]); //Line 7
        Console.WriteLine("[ ]" + breadOptions[5]); //Line 8
        Console.WriteLine("[ ]" + breadOptions[6]); //Line 9
        Console.WriteLine("[ ]" + breadOptions[7]); //Line 10
        Console.WriteLine("[ ]" + breadOptions[8]); //Line 11

        Row = 3; //set the row to the first bread option
        int currentBread = 0; //a couter to keep track of the bread
        ConsoleKeyInfo breadKey = new ConsoleKeyInfo();

        do
        {   //Loop that goes with the cursor through the menu items
            for (Row = 3; Row < breadOptions.Length + 3; Row++)
            {
                //Highlight the current bread with the cursor in the box
                if (currentBread == Row - 3)
                    Console.SetCursorPosition(1, Row);
            }

            //reads the key
            breadKey = Console.ReadKey();
            switch (breadKey.Key)
            {
                case ConsoleKey.DownArrow:
                    //if the current item is the last one in the array, reset the counter.
                    if (currentBread == breadOptions.Length - 1)
                        //-1 because currentBread follows the array, and array starts at 0
                        //but the array lengh doensn't start at 0. 0 is an empty array
                        currentBread = 0;
                    //otherwise, add one to the counter
                    else
                        currentBread++;
                    break;

                case ConsoleKey.UpArrow:
                    //if the user presses Up in the first option, it goes to the last
                    if (currentBread == 0)
                        currentBread = breadOptions.Length - 1;
                    //otherwise, remove one from the counter
                    else
                        currentBread--;
                    break;
            }

        }
        //keep looping until the user presses enter
        while (breadKey.Key != ConsoleKey.Enter);

        Console.SetCursorPosition(0, 12); //set the cursor back to the next line after the last Console.WriteLine

        //make a string to store the selected bread and make it be the selected bread
        string bread = breadOptions[currentBread];

而且,这个do-while循环又重复了几次,这是另一个例子:

//Bread Size
        string[] sizeOptions = { "6-inches", "Footlong"};

        Console.WriteLine(); //Line 12
        Console.WriteLine("Choose a bread size."); //Line 13
        Console.WriteLine("[ ]" + sizeOptions[0]); //Line 14
        Console.WriteLine("[ ]" + sizeOptions[1]); //Line 15

        Row = 14;
        int currentSize = 0;
        ConsoleKeyInfo sizeKey = new ConsoleKeyInfo();

        do
        {
            for (Row = 14; Row < sizeOptions.Length + 14; Row++)
            {
                if (currentSize == Row - 14)
                    Console.SetCursorPosition(1, Row);
            }

            sizeKey = Console.ReadKey();
            switch (sizeKey.Key)
            {
                case ConsoleKey.DownArrow:
                    if (currentSize == sizeOptions.Length - 1)
                        currentSize = 0;
                    else
                        currentSize++;
                    break;
                case ConsoleKey.UpArrow:
                    if (currentSize == 0)
                        currentSize = sizeOptions.Length - 1;
                    else
                        currentSize--;
                    break;
            }
        } while (sizeKey.Key != ConsoleKey.Enter);

        Console.SetCursorPosition(0, 16);

        string size = sizeOptions[currentSize];

我想知道是否有办法在每次需要选择选项时不编写此循环。

【问题讨论】:

标签: c# loops console console-application do-while


【解决方案1】:

您可以使用一种方法来做到这一点:

    int GetOption(int startRow, string[] options)
    {
        int currentOption = 0;
        ConsoleKeyInfo sizeKey = new ConsoleKeyInfo();

        do
        {
            for (int i = startRow; i < options.Length + startRow; i++)
            {
                if (currentOption == i - startRow)
                    Console.SetCursorPosition(1, i);
            }

            sizeKey = Console.ReadKey();
            switch (sizeKey.Key)
            {
                case ConsoleKey.DownArrow:
                    if (currentOption == options.Length - 1)
                        currentOption = 0;
                    else
                        currentOption++;
                    break;
                case ConsoleKey.UpArrow:
                    if (currentOption == 0)
                        currentOption = options.Length - 1;
                    else
                        currentOption--;
                    break;
            }
        } while (sizeKey.Key != ConsoleKey.Enter);

        return currentOption;
    }

用法:

    string[] sizeOptions = { "6-inches", "Footlong"};
    Console.WriteLine(); //Line 12
    Console.WriteLine("Choose a bread size."); //Line 13
    Console.WriteLine("[ ]" + sizeOptions[0]); //Line 14
    Console.WriteLine("[ ]" + sizeOptions[1]); //Line 15

    Row = 14;
    int currentSize = GetOption(Row, sizeOptions);
    Console.SetCursorPosition(0, 16);
    string size = sizeOptions[currentSize];

我现在不能测试它,但我希望它对你有帮助!

【讨论】:

    【解决方案2】:

    取出您想要重用的代码块并将其移至不带参数的新方法中。就像你写出选项的那部分一样。

    问问自己,其他场景不想想要那样的方法中有什么。在选项列表场景中,从一个地方到另一个地方不同的东西是实际的东西列表。所以我们需要把那个东西变成一个变量(这样命名是因为值可以变化)。具体来说,如果您将事物列表作为方法的参数,那么您可以从每个不同的地方调用该方法,并传递相关列表。

    请注意,这样做可能会导致您遇到其他问题。例如,在您打印列表的位置,您当前正在对要打印的每个索引进行硬编码,因此您需要找到一种更灵活的方式来执行此操作 - 一种列出集合中所有项目的方法,无论那里有多少是。尝试查找 foreach 作为这样做的一种方式。

    将代码从一个地方移动到另一个地方以使其变得更好称为重构,这是软件开发中学习的一项非常重要的技能。我只展示了重构时出现的一种问题,但这是一个很大的话题。希望这会有所帮助。

    【讨论】:

    • Nathalia 的回答已经对代码的一部分进行了重构。我的尝试向您展示如何 进行重构。 给一个人一条鱼,你喂他一天;教人钓鱼,你养他一辈子。
    • 你很好地指出了方向并谈论了重构。我同意答案的路径很重要。但是对于正在学习的人来说,有时通过示例来可视化事物会更容易,而不仅仅是描述。尤其是当我们谈论像编程这样抽象的东西时。你不能只凭理论教别人如何钓鱼,对吧?我们的答案相辅相成,在一起会更好。 (:
    • foreach 确实有助于使代码更清晰。谢谢!
    • 我想你们会很自豪的。 Heres my current code now
    • @ThalesVilela 这是一个好的开始。这里仍然有可以重构的重复模式。看看您是否可以将foreach 移动到方法中:这将使代码更加简单。总之,干得好!
    猜你喜欢
    • 2011-11-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-29
    • 1970-01-01
    相关资源
    最近更新 更多