Skip to main content
1 of 5
JD.B
  • 382
  • 1
  • 9

The repeat variable is sticking out to me. It is declared at the top, but only used in one of the case statements. Using a break statement to control the do-while loop would be a cleaner approach.

case "1":
    do
    {
        b.addBook();
        Console.WriteLine("What do you want to do now?");
        Console.WriteLine("Add another book? - Press 1.");
        Console.WriteLine("Go back to main menu? - Press any other button.");
        ConsoleKeyInfo keyPressed;
        keyPressed = Console.ReadKey();
        if (keyPressed.Key != ConsoleKey.D1 && keyPressed.Key != ConsoleKey.NumPad1)
        {
            Console.Clear();
            break;
        }
    } while (true);
                
    Console.Clear();
    this.mainMenu(b);
    break;

The next issue with the code is the line this.mainMenu(b);. This causes a recursive call that can fill the stack if called many many times (via the input "1" -> "any key but 1" -> repeat).

A way to address this is to remove the line this.mainMenu(b);, make this mainMenu(...) function private and create a different public method that repeats the call to mainMenu(...).

Finally, we can add some helper functions with decent names and enums to help define what case "1": actually means. This helps to eliminate the magic, hard-coded, numbers to some degree (they are just a nature of the beast when dealing with these types of menus).

When we put this all together, we get a different approach that may work better. Remember that this is only based on the code I've seen, so take it as an example/another way to do the same thing, not an objectively better solution.

// Map user input (0, 1, 2...) to human-readable action names
// The actions should match up with the menuText string.
private enum MainMenuAction : int
{
    invalid = 0,
    repeat = 1,

    addBook = 1,
    deleteBook = 2,
    // etc..
    exit = 7,
}

// What we want our main menu to say.
// The numbers should match up with the MainMenuAction enum.
private static readonly string menuText =
    "Welcome to Library.\n" +
    "What do you want to do?\n" +
    "1. Add a book.\n" +
    "2. Delete a book.\n" +
    "TODO etc... fill it out here\n" +
    "7. Exit.";

public void mainMenu(BookList bookList)
{
    // Do our application-level looping here
    do
    {
        // Display the main menu text
        Console.WriteLine(menuText);

        // Get the user input
        int userChoice;
        if (tryGetInput(out userChoice))
        {
            // If user wants to exit, then exit the main menu.
            if (userChoice == (int)MainMenuAction.exit)
            {
                break;
            }

            // Handle the user input by casting the int to a human-readable name
            handleMainMenuAction((MainMenuAction)userChoice, bookList);
        }
        else
        {
            // TODO Handle unexpected input (parsing to int failed, user error)
        }
    } while (true);
}

private void handleMainMenuAction(MainMenuAction action, BookList bookList)
{
    // Ensure that the enum is defined
    if (!Enum.IsDefined(typeof(MainMenuAction), action))
    {
        // TODO Handle undefined enum (user error)
        return;
    }

    switch (action)
    {
        case MainMenuAction.addBook:

            // Command-level looping
            do
            {
                bookList.addBook();
            } while (askUserForRepeat("Add another book"));
            break;

        case MainMenuAction.deleteBook:
            bookList.deleteBook();
            break;

        case MainMenuAction.invalid:
        default:
            // TODO Handle invalid action (internal error -- not yet implmented, probably)
            break;
    }
}

// Just a wrapped version of int.TryParse that grabs from the command line
private bool tryGetInput(out int input)
{
    return int.TryParse(Console.ReadLine(), out input);
}

// Displays 'repeatText' as the first option, the second option is to go back to the main menu
// Basically a yes/no continue loop where 1 = continue and anything else = quit
private bool askUserForRepeat(string repeatText)
{
    Console.WriteLine("1. " + repeatText);
    Console.WriteLine("2. Back to Main Menu");

    int userInput;
    if (tryGetInput(out userInput))
    {
        if (userInput == (int)MainMenuAction.repeat)
        {
            return true;
        }
        else
        {
            // Go back to main menu -- user ended repeat.
            return false;
        }
    }
    else
    {
        // Go back to main menu -- invalid user input.
        return false;
    }
}
JD.B
  • 382
  • 1
  • 9