【问题标题】:Creating A Command Based Application Without Extensive Use Of If-Else Statements在不广泛使用 If-Else 语句的情况下创建基于命令的应用程序
【发布时间】:2016-09-01 00:06:55
【问题描述】:

我有这个 C# 应用程序我想处理。它主要是基于命令的,我的意思是用户输入某种类型的命令,应用程序只是执行某种任务。

例如:用户可以输入一个命令,例如getdate,应用程序读取这个命令并简单地显示一个日期。

注意:它将是基于控制台的,但我的问题是,实际的应用程序有大约 80 到 100 个命令,我的问题是如何在不依赖一些冗长的 if-else 语句来检查输入的命令的情况下读取此命令。

有没有办法可以做到这一点,或者我只需要使用一些长的 if-else 语句。

【问题讨论】:

  • 它不一定不那么冗长,但你可以看看使用switch 语句。您也许可以使用 Dictionary<K, V> 之类的东西,但我不确定您如何以优雅的方式将其连接到实际的代码逻辑,除非值是某种类型的 Func

标签: c#


【解决方案1】:

您可以采取多种选择:

  • 您可以有一个映射到要初始化的类型的命令的 hastable。

    Dictionary<string, Type> 其中类型映射到您初始化的类。

  • 使用反射将命令直接映射到要初始化的对象(通过对象名称或属性。

    [Command(Name = "update")]
    public class RunUpdates : ICommand {
    
    }
    
    [Command(Name = "restart")]
    public class RestartServer : ICommand {
    
    }
    

然后使用反射找到实现ICommand且属性与命令名匹配的对象。

【讨论】:

    【解决方案2】:

    使用简单形式的命令模式以及某种命令集合。

    一种简单的构建方法是:

    public class MyApp
    {
        private readonly Dictionary<string, Action> _commands = new Dictionary<string, Action>();
    
        public static void Main()
        {
            var program = new MyApp();
            // Run Console Stuff
        }
    
        public MyApp()
        {
            SetupCommands();
        }
    
        public void SetupCommands()
        {
            _commands.Add("PrintDate", () => Console.WriteLine(DateTime.Now));
            _commands.Add("PrintMaxOf3And7", () => Console.WriteLine(Math.Max(3, 7)));
        }
    
        public void ExecuteCommand(string commandName)
        {
            _commands[commandName].Invoke();
        }
    }
    

    【讨论】:

      【解决方案3】:

      使用委托:

      public delegate void CommandDelegate(string input);
      
      public Dictionary<string, CommandDelegate> Commands { get; set; }
      
      /// usage
      public void InitCommands() 
      {
          Commands.Add("showdata", (input) => Console.WriteLine(....));
          ... // other commands
      }
      
      public void ExecuteCommand(string userInput) 
      {
          var firstWord = userInput.Substring(0, userInput.IndexOf(" "));
          if (Commands.ContainsKey(firstWord)) 
          {
               var command = Commands[firstWord];   
               command(userInput);
          }
      }
      

      【讨论】:

        【解决方案4】:

        您可以使用将string 用作键和方法(Action、Func 或自定义委托)作为值的字典,然后您只需要读取用户的输入并使用它作为键键来获取相应的动作。如果命令可以有像command param1这样的参数,那么使用string.Split将命令与参数分开,然后使用命令字符串作为键,在执行方法时传递另一个字符串作为参数(取决于类型参数的数据可能需要将命令的参数从字符串解析为其他内容)

        代码如下所示:

        使用函数:

        注意:Func 至少需要一个参数和一个返回值。

        void Main()
        {
            public Dictionary<string, Func<string, int>> commands =
                                           new Dictionary<string, Func<string, int>>();
            commands.Add("getdate", GetDate);
        
            Console.WriteLine("Enter a command");
            string input = Console.ReadLine(); //<-- Try typing "getdate"
            commands[input].Invoke();
        }
        
        public int GetDate(string someParameter)
        {
           Console.WriteLine(DateTime.Today);
           return 0;
        }
        

        使用动作:

        注意:Action 至少需要一个参数。

        void Main()
        {
            public Dictionary<string, Action<string>> commands = new Dictionary<string, Action>();
            commands.Add("getdate", GetDate);
        
            Console.WriteLine("Enter a command");
            string input = Console.ReadLine(); //<-- Try typing "getdate"
            commands[input].Invoke();
        }
        
        public void GetDate(string someParameter)
        {
           Console.WriteLine(DateTime.Today);
        }
        

        使用自定义委托:

        public delegate double YourDelegate(string param);
        
        void Main()
        {
            public Dictionary<string, YourDelegate> commands = 
                                                new Dictionary<string, YourDelegate>();
            commands.Add("getdate", GetDate);
        
            Console.WriteLine("Enter a command");
            string input = Console.ReadLine(); //<-- Try typing "getdate"
            commands[input].Invoke();
        }
        
        public double GetDate(string someParameter)
        {
           Console.WriteLine(DateTime.Today);
           return 0.0;
        }
        

        【讨论】:

        • FuncAction 都不需要至少 1 个参数。没有任何参数,两者都可以正常工作。但是,在这种特定情况下,可能希望将命令的其余部分作为字符串传递。
        【解决方案5】:

        您可以使用 switch,也可以创建一个以问题为键、命令为值的字典。建议您对键和输入都执行 ToLower() 以使其不区分大小写,因为依靠用户完美输入会很困难。

        private Dictionary<string,object> commandList = new Dictionary<string,object>();
        private void processCommand(){
        commandList.Add("showdate",DateTime.Now);
        string command = Console.ReadLine();
        if(command.Length>0){
            if(commandList.ContainsKey(command);
                 object o = commandList[command.ToLower()];
                 //do something
            }
        }
        }
        

        【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-06-01
        • 1970-01-01
        • 2012-12-13
        • 2016-10-13
        相关资源
        最近更新 更多