【问题标题】:Is it possible to avoid multiple IFs in this code?是否可以在此代码中避免多个 IF?
【发布时间】:2012-08-12 14:06:56
【问题描述】:

我有这样的代码和平。我必须检查 XML 中的每个级别以避免 NULL 异常。我可以改进这段代码吗?

private void GetFunctionsValues(XElement x)
    {
        if (x.Element("credentials") != null)
        {
            if (x.Element("credentials").Element("faccess") != null)
            {
                foreach (var access in x.Element("credentials").Element("faccess").Elements("access"))
                {
                    if (access.Attribute("db_id") != null)
                    {
                        if (int.Parse(access.Attribute("db_id").Value) == 19) FuncPlus = true;
                    }
                }
            }
        }
    }

【问题讨论】:

  • if (x.Element("credentials") != null && x.Element("credentials").Element("faccess") != null) 一个如果没有:)

标签: c# if-statement


【解决方案1】:

您可以将两个嵌套的if 合并为一个:

if (x.Element("credentials") != null && x.Element("credentials").Element("faccess") != null )

第一个评估为 false 阻止执行第二个,因此没有空引用异常。这种行为通常被称为“短路评估”:当程序明白它可以跳过if时,它会停止评估剩余部分。

【讨论】:

    【解决方案2】:

    我相信这是最简单的选择:

        private void GetFunctionsValues(XElement x)
        {
            var el = x.XPathSelectElement(@"credentials/faccess/access[@db_id=19]");
            if(el != null)
                FuncPlus = true;
        }
    

    XPathSelectElementSystem.Xml.XPath 命名空间中声明。

    【讨论】:

    • 这正是我想要的!它又短又漂亮。谢谢你,伊万! :-)
    • 小改进:FuncDocGenPlus = el != null;现在这些线条是完美的! :)
    【解决方案3】:

    我有一个扩展方法可以使这样的代码更具可读性:

     public static TResult Access<TSource, TResult>(
               this TSource obj, 
               Func<TSource, TResult> expression, 
               TResult defaultValue = default(TResult)) where TSource : class
        {
            if (obj == null)
            {
                return defaultValue;
            }
    
            return expression.Invoke(obj);
        }
    

    在这种情况下,您可以流畅地编写访问某些属性:

    var faccessElement = x
             .Access(y => y.Element("credentials"))
             .Access(y => y.Element("faccess"));
    if (faccessElement != null) 
    {
        //...
    }
    

    【讨论】:

      【解决方案4】:

      您可以合并一些if()s,因为布尔运算具有定义的运算顺序(从左到右):

      而不是这样写:

      if (condition_a)
          if (condition_b)
              action();
      

      你可以简单地使用这个:

      if (condition_a && condition_b)
           action();
      

      只要确保您仍然首先验证您的对象存在,然后执行进一步检查。

      【讨论】:

        【解决方案5】:

        您至少可以通过将前两个ifs 合并为一个并将属性的选择放入foreach 循环中的查询中来使其更紧凑:

        private void GetFunctionsValues(XElement x) 
        { 
            if (x.Element("credentials") != null
                && x.Element("credentials").Element("faccess") != null) 
            { 
                foreach (var attribute in x.Element("credentials")
                                           .Element("faccess")
                                           .Elements("access")
                                           .Select(x => x.Attribute("db_id"))
                                           .Where(x => x != null)) 
                { 
                    if (int.Parse(attribute.Value) == 19) FuncPlus = true; 
                } 
            } 
        } 
        

        请参阅this answer,了解为什么可以将前两个ifs 合并为一个。

        【讨论】:

          【解决方案6】:

          如果要改进它并结合两者,你可以尝试

          private void GetFunctionsValues(XElement x)
          {
              var credentialsElement = x.Element("credentials") ;
              if (credentialsElement != null && credentialsElement.Element("faccess") != null)
              {
                   foreach (var access in credentialsElement.Element("faccess").Elements("access"))
                   {
                       if (access.Attribute("db_id") != null)
                       {
                           if (int.Parse(access.Attribute("db_id").Value) == 19) FuncPlus = true;
                       }
                   }
               } 
          }
          

          【讨论】:

            【解决方案7】:

            我经常发现使用 return 而不是 imbrication 代码更具可读性:

            private void GetFunctionsValues(XElement x)
            {
                if (x.Element("credentials") == null || x.Element("credentials").Element("faccess") == null) return;
                foreach (var access in x.Element("credentials").Element("faccess").Elements("access"))
                {
                    if (access.Attribute("db_id") != null && int.Parse(access.Attribute("db_id").Value) == 19)
                    {
                        FuncPlus = true;
                        return; // it seems we can leave now !
                    }
                }
            }
            

            然后看看我在条件验证后添加的返回:我认为你不需要继续迭代。

            【讨论】:

              【解决方案8】:

              如果是我,我会这样写:

              private void GetFunctionsValues(XElement x)
              {
                  if (x.Element("credentials") == null
                  || x.Element("credentials").Element("faccess") == null)
                     return;
              
                  bool any = 
                     x
                     .Element("credentials")
                     .Element("faccess")
                     .Elements("access")
                     .Where(access => access.Attribute("db_id") != null)
                     .Any(access => int.Parse(access.Attribute("db_id").Value) == 19);
              
                  if (any)
                     FuncPlus = true;
              }
              

              注意事项:

              两个连续的ifs 可以通过用&amp;&amp; 连接它们的表达式来替换。例如:

              if (test1)
                 if (test2)
              
              // becomes
              
              if (text1 && test2)
              

              foreach 后跟 if 可以替换为 LINQ Where 查询。例如:

              foreach (var item in collection)
                 if (item.SomeProperty == someValue)
                    action(item);
              
              
              // becomes
              
              collection
              .Where(item => item.SomeProperty == someValue)
              .ForEach(action);
              

              在执行某些操作之前进行的测试通常最好倒写,以避免过度嵌套。例如:

              if (test1)
                 if (test2)
                    if (test3)
                       doSomething();
              
              // becomes
              
              if (!(test1 || test2 || test3))
                 return;
              
              doSomething();
              

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 2020-09-16
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2013-09-17
                • 1970-01-01
                相关资源
                最近更新 更多