制作控制台菜单的“正确”方法是什么?

时间:2018-11-09 22:27:04

标签: c# menu console-application

我的任务是编写一个程序,该程序向用户提供带有4个选项的菜单,然后接受输入并使用输入进行一些计算。最好的方法是什么?

作为参考,我的方法是使用所有菜单选项制作一个enum,并使其控制switch语句来控制操作。

    private enum MainMenu
    {
        CYLINDER = 1,
        CUBE,
        SPHERE,
        QUIT,
        UNASSIGNED
    }
    MainMenu mmChoice = MainMenu.UNASSIGNED;
    string sInput = Console.ReadLine();
    switch (mmChoice)
    {
        case MainMenu.CYLINDER:
            doWork1();
            break;
        case MainMenu.CUBE:
            doWork2();
            break;
        case MainMenu.SPHERE:
            doWork3();
            break;
        case MainMenu.QUIT:
            Exit();
            break;
        case MainMenu.UNASSIGNED:
            break;
    }

案例中发生的事情并不重要,但我想知道如何从句法上进行这项工作。由于我使用的是来自用户的输入(由Console.ReadLine()获取,该输入返回了string,并且我需要以enum的形式输入),所以我不知道该如何进行。如何将sInput与mmChoice相关联并操作开关?

我知道这是在问两个问题,但是出于任务的目的,我希望有人回答具体情况,也许有人可以在评论中告诉我最好的一般方法。

3 个答案:

答案 0 :(得分:0)

像Rufus L(How should i convert a string to an enum in C#?)这样的

在注释中已经指出: 您要做的就是分别使用TryParse / Parse将输入转换为枚举

请注意,建议在处理用户输入时使用TryParse(或者几乎在您无法保证解析将起作用的任何其他时间)。

        MainMenu mmChoice = MainMenu.UNASSIGNED;
        Console.WriteLine("?");
        string sInput = Console.ReadLine();
        if(Enum.TryParse(sInput, out mmChoice))
        {
            switch(mmChoice)
            {
                case MainMenu.CYLINDER:
                    Console.WriteLine("cylinder");
                    break;
                case MainMenu.CUBE:
                    Console.WriteLine("cube");
                    break;
                case MainMenu.SPHERE:
                    Console.WriteLine("sphere");
                    break;
                case MainMenu.QUIT:
                    Console.WriteLine("quit");
                    break;
                case MainMenu.UNASSIGNED:
                    break;
            }
        }

EDIT : 由于OP在评论中要求使用基于字符的解决方案:

        Console.WriteLine("?");
        char sInput = Console.ReadKey().KeyChar;
        Console.WriteLine("");
        switch (sInput)
        {
            case 'a':
                Console.WriteLine("cylinder");
                break;
            case 'b':
                Console.WriteLine("cube");
                break;
            case 'c':
                Console.WriteLine("sphere");
                break;
            case 'd':
                Console.WriteLine("quit");
                break;
            default :
                break; // error handling here
       }

答案 1 :(得分:0)

仅仅是有趣的,面向对象的方法

public interface IJob
{
    void Do();
}

public class JobOne : IJob
{
    public void Do()
    {
        // do something
    }
}

public class JobTwo : IJob
{
    public void Do()
    {
        // do something different
    }
}

public class DoNothing : IJob
{
    public void Do() { }
}

public class JobRunner
{
    private readonly Dictionary<string IJob> _jobs;
    private readonly IJob _doNothing;

    public JobRunner()
    {
        _jobs = new Dictionary<string, IJob>
        {
            { "one", new JobOne() },
            { "two", new JobTwo() },
        };
        _doNothing = new DoNothing();
    }

    public void Run(string jobKey)
    {
        _jobs.GetValueOrDefault(jobkey, _doNothing).Do();
    }
}

用法如下:

vr runner = new JobRunner();

var input = Console.ReadLine();
runner.Run(input);

答案 2 :(得分:0)

这是另一种方法,该方法是创建一个表示MenuItem的类,该类具有说明和相关的方法(如果选择了该项目,则应调用该方法)。

private class MenuItem
{
    public string Description { get; set; }
    public Action Execute { get; set; }
}

然后,我们可以填充这些项目的列表,以显示在MainMenu

// Our private list of menu items that will be displayed to the user
private static List<MenuItem> MenuItems;

// A helper method to populate our list. 
// We can easily add or remove new items to the menu
// without having to worry about changing an 
// enum or adding a command to a switch block
private static void PopulateMenuItems()
{
    MenuItems = new List<MenuItem>
    {
        new MenuItem {Description = "View balance", Execute = ViewBalance},
        new MenuItem {Description = "Deposit", Execute = Deposit},
        new MenuItem {Description = "Withdraw", Execute = Withdraw},
    };
}

请注意,每个项目都具有Execute类型的Action属性,并且在上面为其分配了值。这些值实际上是可以在项目中其他位置定义的方法。当前,每个方法只是一个存根,它调用一个帮助程序方法以显示标题,另一个调用帮助程序方法以提示用户返回主菜单,但是它们可能包含实际功能:

private static void ViewBalance()
{
    ClearAndShowHeading("Account Balance");
    GoToMainMenu();
}

private static void Deposit()
{
    ClearAndShowHeading("Account Deposit");
    GoToMainMenu();
}

private static void Withdraw()
{
    ClearAndShowHeading("Account Withdrawl");
    GoToMainMenu();
}

private static void ClearAndShowHeading(string heading)
{
    Console.Clear();
    Console.WriteLine(heading);
    Console.WriteLine(new string('-', heading?.Length ?? 0));
}

private static void GoToMainMenu()
{
    Console.Write("\nPress any key to go to the main menu...");
    Console.ReadKey();
    MainMenu();
}

因此,既然我们有了菜单项的列表,我们就可以创建一个方法来显示它们,这也将获得用户选择的菜单项的输入,然后调用关联的方法(通过{{1} }属性。

请注意,此处还进行了一些验证,以确保用户仅选择有效的项目。我们根据列表中的索引显示项目(将索引添加到索引中,这样列表就不会以Execute开头),然后将用户输入传递给0.方法。此方法将尝试将用户的输入解析为整数。如果解析成功,则该方法返回int.TryParse(并且退出循环),并且true参数将包含该值。

这是在循环内完成的,因此,如果用户输入了无效的数字,则我们将光标设置回该行的开头,在其上写空格,然后再次将光标设置回该行的开头,提示他们输入:

out

现在,通过这种方式,自定义菜单项,向用户显示菜单项并相应地执行正确的方法非常容易:

static void MainMenu()
{
    ClearAndShowHeading("Main Menu");

    // Write out the menu options
    for (int i = 0; i < MenuItems.Count; i++)
    {
        Console.WriteLine($"  {i + 1}. {MenuItems[i].Description}");
    }

    // Get the cursor position for later use 
    // (to clear the line if they enter invalid input)
    int cursorTop = Console.CursorTop + 1;
    int userInput;

    // Get the user input
    do
    {
        // These three lines clear the previous input so we can re-display the prompt
        Console.SetCursorPosition(0, cursorTop);
        Console.Write(new string(' ', Console.WindowWidth));
        Console.SetCursorPosition(0, cursorTop);

        Console.Write($"Enter a choice (1 - {MenuItems.Count}): ");
    } while (!int.TryParse(Console.ReadLine(), out userInput) ||
             userInput < 1 || userInput > MenuItems.Count);

    // Execute the menu item function
    MenuItems[userInput - 1].Execute();
}

尝试一下,看看您的想法。菜单将如下所示:

enter image description here

现在,如果我们要添加新的菜单项怎么办?简单!在代码块中添加以下行,我们在static void Main(string[] args) { PopulateMenuItems(); MainMenu(); Console.Write("\nDone! Press any key to exit..."); Console.ReadKey(); } 方法内将项目分配给MenuItems,然后再次运行它:

PopulateMenuItems

现在我们的菜单如下:

enter image description here