【问题标题】:C# Better way to handle multiple if/else if statementsC# 处理多个 if/else if 语句的更好方法
【发布时间】:2016-07-11 14:21:27
【问题描述】:

我有一个类来处理传入的无线消息并解析它们。根据命令的输出,我需要处理一些 UI 修改,例如突出显示标签、向文本框添加文本等。我​​使用的第一个选项是:

void IncomingMessageIfStatements(Message msg, Host host)
        {
            byte resp;
            if (ParseMessageOptionOne(msg, out resp))
            {
                // Do some windows form stuff
            }    

            else if (ParseMessageOptionTwo(msg, out resp))
            {
                // Do some windows form stuff
            }

            else if (ParseMessageOptionThree(msg, out resp))
            {
                // Do some windows form stuff
            }
        }

        private bool ParseMessageOptionOne(Message msg, out byte resp)
        {
            throw new NotImplementedException();
        }
        private bool ParseMessageOptionTwo(Message msg, out byte resp)
        {
            throw new NotImplementedException();
        }
        private bool ParseMessageOptionThree(Message msg, out byte resp)
        {
            throw new NotImplementedException();
        }

这行得通,但我会有更多else if 声明,它可能会变得丑陋。我看的下一个方法是:

void IncomingMessageSwitchStatements(Message msg, Host host)
        {
            byte resp = 0;
            byte someByte = 0;
            bool output = false;
            switch (someByte)
            {
                case 1:
                    output = ParseMessageOptionOne(msg, out resp);
                    break;
                case 2:
                    output = ParseMessageOptionTwo(msg, out resp);
                    break;
                case 3:
                    output = ParseMessageOptionThree(msg, out resp);
                    break;
                default:
                    //handle exception here
                    break;
            }

            if (output && resp == 0x01)
            {
                UpdateUiFromHere();
            }
        }

        private void UpdateUiFromHere()
        {
            // handle UI updates here
        }

这看起来更干净并且可以按预期工作。但后来我开始关注Dictionary<byte, Func<bool>>,并认为这可能是解决处理传入的多个条件(可能是 20 个)的更好方法。

对于我应该采用的最佳实践有什么建议吗?

【问题讨论】:

  • switch 版本将始终执行默认分支...你说它按预期工作?
  • 似乎“if else”块在逻辑上与“switch case”块不同。 ParseMessageOptionX 返回 bool,someByte 来自哪里?
  • switch 比 if/else if/else 好。但是,如果有大量的条件,那么查找表(字典)将使您的代码更简洁。
  • 你应该看看programmers.stackexchange.com/questions/206816/…我认为如果你有超过10个if-condition或case-switch,你可以用多态替换它们
  • @DiligentKeyPresser 出于安全原因,我提取了一些代码,但case 是为了清楚起见。 case 显然是基于来自消息的byte

标签: c# winforms if-statement dictionary switch-statement


【解决方案1】:

由于您要做的是“根据索引号调用具有相同签名的方法”,因此您可以使用 delegate 并将它们列在 Dictionary 中(如果索引从0) 表明你的意图。

public delegate bool ParseMessage(Message msg, out byte resp);

然后使用Dictionary列出它:

Dictionary<byte, ParseMessage> parser = new Dictionary<byte, ParseMessage>(){
    {1, new ParseMessage(ParseMessageOptionOne)},
    {2, new ParseMessage(ParseMessageOptionTwo)},
    {3, new ParseMessage(ParseMessageOptionThree)}
};

或使用List

List<ParseMessage> parser = new List<ParseMessage>(){
    new ParseMessage(ParseMessageOptionOne),
    new ParseMessage(ParseMessageOptionTwo),
    new ParseMessage(ParseMessageOptionThree)
};

然后这样称呼它:

bool result = parser[resp](msg, out resp); //dictionary
bool result = parser[resp-1](msg, out resp); //list

【讨论】:

    【解决方案2】:

    我会将解析移到内部 Message 类本身。

    Options option = msg.GetOption();
    

    我也会为你的所有选项做一个枚举:

    public enum Options {
        One,
        Two,
        None
    }
    

    然后编写您的代码以使用它,但是您需要...

    if (option == Options.One)
    // or
    switch(option)
    // etc.
    

    很难推荐更多,因为我不知道 UpdateUiFromHere() 做了什么,因为它不需要任何参数......但这应该是一些值得思考的好东西。

    【讨论】:

    • 这些是编写自文档代码的好建议,但不能解决 OP 的问题。
    • @JonathanWood,OPs 的问题几乎足以要求改写或关闭过于宽泛:“关于我应该采用的最佳实践的任何建议,考虑到需要什么?”我的回答更像是使用encapsulation,因此 Message 类包含所有逻辑,这将是“最佳实践”。有些问题很难决定回答问题 X,或者帮助解决问题 Y(有时 OP 可能不会直接在 X 中询问)。
    【解决方案3】:

    您也可以更改 ParseMessageOptionOne、ParseMessageOptionTwo、ParseMessageOptionThree 的方法签名,返回一个封装了输出、响应的响应对象,并使用 Func 内置委托来存储方法:

    public struct ParseResponse
    {
        public bool output;
        public byte response;
    }
    
    class ParseOptions
    {
        Func<Message, ParseResponse>[] options = null;
    
        public ParseOptions()
        {
            options = new Func<Message, ParseResponse>[]{
                ParseMessageOptionOne,
                ParseMessageOptionTwo,
                ParseMessageOptionThree
            };
        }
    
        public void IncomingMessageSwitchStatements(Message msg, Host host)
        {            
            byte someByte = 2;
    
            var response = options[someByte](msg);
    
            if (response.output && response.response == 0x01)
            {
                //UpdateUiFromHere();
            }
        }
    
        private ParseResponse ParseMessageOptionThree(Message msg)
        {
            return new ParseResponse { output = true };
        }
    
     }
    

    【讨论】:

      【解决方案4】:

      另一种选择是使用 LINQ 循环遍历委托方法列表,并在找到 true 条件后立即进行短路。

      private delegate bool ParseMessageWrapper(Message msg, out byte resp);
      
      void IncomingMessageSwitchStatements(Message msg, Host host)
      {
          byte resp = 0;
          bool output = false;
      
          var parseMethods = new List<ParseMessageWrapper>()
          {
              new ParseMessageWrapper(ParseMessageOptionOne),
              new ParseMessageWrapper(ParseMessageOptionTwo),
              new ParseMessageWrapper(ParseMessageOptionThree)
          };
      
          output = parseMethods.Any(func => func.Invoke(msg, out resp));
      
          if (output && resp == 0x01)
          {
              UpdateUiFromHere();
          }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-07-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-08-29
        • 2015-02-06
        • 2019-04-09
        相关资源
        最近更新 更多