2016-10-25 5 views
1

コンソールにサブメニューを持つメニューを作成しました。すべてうまく動作しますが、私のプログラムの構造を改善することはできないのだろうかと思います。それを単純化し、より一般的にする。私は、サブメニューを追加する必要がある場合Cでメニュー(コンソール)を改善する方法

class MainClass 
{ 
    public static void Main(string[] args) 
    { 
     MainMenu(); 
    } 

    public static void MainMenu() 
    { 
     Console.WriteLine("Main Menu"); 
     Console.WriteLine("--------------------"); 
     Console.WriteLine("[1] Show activities"); 
     Console.WriteLine("[2] Show teachers"); 
     Console.WriteLine("[3] Show students"); 
     Console.WriteLine("[4] Exit the program"); 
     Console.WriteLine("--------------------\n"); 
     Console.WriteLine("Please select an option from 1-4\n"); 

     string choice = Console.ReadLine(); 
     int number; 
     bool result = Int32.TryParse(choice, out number); 
     if (result) 
     { 
      Console.Clear(); 
      SubMenu(number); 
     } 
     else 
     { 
      Console.WriteLine("Incorrect choice"); 
     } 
    } 

    public static void SubMenu(int mainMenuChoice) 
    { 
     switch (mainMenuChoice) 
     { 
      case 1: 
       Console.WriteLine("Activities"); 
       Console.WriteLine("[1] Show all activities"); 
       Console.WriteLine("[2] Find a activity by his code"); 
       Console.WriteLine("[3] Return Main Menu"); 
       Console.WriteLine("[4] Exit the program"); 
       Console.WriteLine("--------------------\n"); 
       Console.WriteLine("Please select an option from 1-4\n"); 
       break; 

      case 2: 
       Console.WriteLine("Teachers"); 
       Console.WriteLine("[1] Show all teachers"); 
       Console.WriteLine("[2] Find a teacher by his matricule"); 
       Console.WriteLine("[3] Return Main Menu"); 
       Console.WriteLine("[4] Exit the program"); 
       Console.WriteLine("--------------------\n"); 
       Console.WriteLine("Please select an option from 1-4\n"); 
       break; 

      case 3: 
       Console.WriteLine("Students"); 
       Console.WriteLine("[1] Show all students"); 
       Console.WriteLine("[2] Find a student by his matricule"); 
       Console.WriteLine("[3] Return Main Menu"); 
       Console.WriteLine("[4] Exit the program"); 
       Console.WriteLine("--------------------\n"); 
       Console.WriteLine("Please select an option from 1-4\n"); 
       break; 

      case 4: 
       Environment.Exit(0); 
       break; 
     } 
     string choice = Console.ReadLine(); 
     int number; 
     bool result = Int32.TryParse(choice, out number); 
     if (result) 
     { 
      Action(mainMenuChoice, number); 
     } 
     else 
     { 
      Console.WriteLine("Incorrect choice"); 
     } 
    } 
    public static void Action(int menu, int choice) 
    { 
     switch (menu) 
     { 
      case 1: 
       switch (choice) 
       { 
        case 1: 
         // Do Stuff 
         break; 

        case 2: 
         // Do Stuff 
         break; 

        case 3: 
         Console.Clear(); 
         MainMenu(); 
         break; 

        case 4: 
         Environment.Exit(0); 
         break; 
       } 
       break; 

      case 2: 
       switch (choice) 
       { 
        case 1: 
         // Do Stuff 
         break; 

        case 2: 
         // Do Stuff 
         break; 

        case 3: 
         Console.Clear(); 
         MainMenu(); 
         break; 

        case 4: 
         Environment.Exit(0); 
         break; 
       } 
       break; 

      case 3: 
       switch (choice) 
       { 
        case 1: 
         // Do Stuff 
         break; 

        case 2: 
         // Do Stuff 
         break; 

        case 3: 
         Console.Clear(); 
         MainMenu(); 
         break; 

        case 4: 
         Environment.Exit(0); 
         break; 
       } 
       break; 
     } 
    } 
} 

現在、私はこのための選択肢があるので、私はできるだけ多くのサブメニュー()関数内でケースを追加する必要があり、メインメニュー()関数に行を追加する必要がありますアクション()内のメニュー。 サブメニューが1つのみの場合は問題ありませんが、ダースを追加する必要がある場合はすぐに管理できなくなります。 私はおそらく1つまたは複数のクラスを通過する必要がありますが、私は構造上失われています。

答えて

1

私はこの問題に対する1つのアプローチを実証するためにすばやく何かを作った。私はコードのほとんどをコメントしましたが、何かが不明であるかどうか尋ねます。私の主な利点は、メニューをオブジェクトとして1か所に宣言できることです。私のコードでは、これをMainメソッドで明示的に行っていますが、メニューを生成するためのファクトリメソッドを簡単に記述することができます。

class Program 
{ 
    //represents a line/option in a menu 
    class MenuItem 
    { 
     // displayed in the menu 
     public string Text { get; set; } 

     //is there a sub menu 
     public bool HasSubMenu { get; set; } 

     // if there's a submenu, what's its id 
     public int? SubMenuId { get; set; } 

     //if there isn't a sub menu, what should we do 
     public Action Action { get; set; } 
    } 

    //represents one menu i.e. a collection of options 
    class Menu 
    { 
     public Menu() 
     { 
      MenuItems = new List<MenuItem>(); 
     } 

     public int MenuId { get; set; } 
     public List<MenuItem> MenuItems { get; set; } 
     public string Title { get; set; } 

     public void PrintToConsole() 
     { 
      foreach (MenuItem item in MenuItems) 
      { 
       Console.WriteLine(MenuItems.IndexOf(item) + " : " + item.Text); 
      } 
     } 
    } 

    //represents all the menus 
    class MenuCollection 
    { 
     public MenuCollection() 
     { 
      Menus = new List<Menu>(); 
     } 

     public List<Menu> Menus { get; set; } 

     public void ShowMenu(int id) 
     { 
      //get the menu we want to display and call its PrintToConsole method 
      var currentMenu = Menus.Where(m => m.MenuId == id).Single(); 
      currentMenu.PrintToConsole(); 

      //wait for user input 
      string choice = Console.ReadLine(); 
      int choiceIndex; 

      //once we have the users selection make sure its an integer and in range of our menu options 
      //if not then show an error message and re-display the menu 
      if (!int.TryParse(choice, out choiceIndex) || currentMenu.MenuItems.Count < choiceIndex || choiceIndex < 0) 
      { 
       Console.Clear(); 
       Console.WriteLine("Invalid selection - try again"); 
       ShowMenu(id); 
      } 
      else 
      { 
       // if the selection is good, then retrieve the corresponding menu item 
       var menuItemSelected = currentMenu.MenuItems[choiceIndex]; 

       // if there's a sub menu then display it 
       if (menuItemSelected.HasSubMenu) 
       { 
        Console.Clear(); 
        ShowMenu(menuItemSelected.SubMenuId.Value); 
       } 
       // otherwise perform whatever action we need 
       else 
       { 
        menuItemSelected.Action(); 
       } 
      } 
     } 
    } 

    static void Main(string[] args) 
    { 
     // build a collection of menus 
     // can have as deep a structure as you like 
     // give each menu a unique integer MenuId 
     // link to other menus by setting HasSubMenu to true, and the SubMenuId to the MenuId of the menu you wish to link to 
     // or, set HasSubMenu to false, and have an Action performed when the menuitem is selected 
     MenuCollection collection = new MenuCollection() 
     { 
      Menus = 
      { 
       new Menu() 
       { 
        MenuId = 1, 
        MenuItems = 
        { 
         new MenuItem() 
         { 
          Text = "Go to sub menu", 
          HasSubMenu = true, 
          SubMenuId = 2 
         }, 
         new MenuItem() 
         { 
          Text = "Print Action", 
          HasSubMenu = false, 
          Action =() => 
          { 
           Console.WriteLine("I printed from an action"); 
          } 
         } 
        } 
       }, 
       new Menu() 
       { 
        MenuId = 2, 
        MenuItems = 
        { 
         new MenuItem() 
         { 
          Text = "Sub menu option 1", 
          HasSubMenu = false, 
          Action =() => 
          { 
           Console.WriteLine("Printed from a sub menu"); 
          } 
         }, 
         new MenuItem() 
         { 
          Text = "Back to the top menu", 
          HasSubMenu = true, 
          SubMenuId = 1 
         } 
        } 
       } 
      } 
     }; 

     collection.ShowMenu(1); 
     Console.ReadLine(); 
    } 
} 
+0

ご回答ありがとうございます。私はこのアプローチが好きです。 – bluebeel

0

私は最近、小さなCLIツールをたくさん作ってきた、私は活動を肉付けが、ここで私は、一般的にメニュー/分岐ロジックをたくさんのために利用したいアプローチの例です:

class Program 
{ 

    static T GetChoice<T>(List<Tuple<string, T>> choices) 
    { 
     var i = 1; 
     choices.ForEach(x => Console.WriteLine($"[{i++}]: {x.Item1}")); 
     var choiceIndex = int.Parse(Console.ReadLine()); 
     return choices[choiceIndex - 1].Item2; 
    } 

    static void Main(string[] args) 
    { 
     Console.WriteLine("Main Menu: "); 
     var choices = new List<Tuple<string, Action>>() 
     { 
      new Tuple<string, Action>("Show Activities", ShowActivities), 
      new Tuple<string, Action>("Show Teachers", ShowTeachers), 
      new Tuple<string, Action>("Show Students", ShowStudents), 
      new Tuple<string, Action>("Exit", Exit), 
     }; 

     GetChoice(choices)(); 
    } 

    static void ShowActivities() 
    { 
     Console.WriteLine("Activities: "); 
     var choices = new List<Tuple<string, Action>>() 
     { 
      new Tuple<string, Action>("Show all activities", ShowAllActivities), 
      new Tuple<string, Action>("Find activity by code", FindActivityByCode), 
      new Tuple<string, Action>("Return to main menu",() => { Main(null); }), 
      new Tuple<string, Action>("Exit the program", Exit), 
     }; 

     GetChoice(choices)(); 
    } 

    static void ShowTeachers() 
    { 
     Console.WriteLine("Teachers: "); 
     var choices = new List<Tuple<string, Action>>(); 
    } 

    static void ShowStudents() 
    { 
     Console.WriteLine("Students: "); 
     var choices = new List<Tuple<string, Action>>(); 
    } 

    static void ShowAllActivities() 
    { 
     //Do stuff 
    } 

    static void FindActivityByCode() 
    { 
     //Do stuff 
    } 

    static void ReturnToMainMenu() 
    { 
     //Do stuff 
    } 

    static void Exit() 
    { 
     Environment.Exit(0); 
    } 
} 
+0

お返事ありがとうございました。私はあなたのGetChoiceメソッドの作成を理解していません。これは一般的な方法ですが、メソッド名の前にTはありますか? 通常これはそうではありません:static GetChoice ? – bluebeel

+0

これはジェネリック型を返すことを意味します。たとえば、名前や何かを選択したい場合はTuple のリストでGetChoiceを実行します。必要な場合はTupleのリストでGetChoiceをアクティビティIDのリストなどから整数を選択します。 – ivanPfeff

関連する問題