是否可以避免此代码中的多个IF?

时间:2012-08-16 08:45:34

标签: c# if-statement

我有这种代码的和平。我必须检查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;
                    }
                }
            }
        }
    }

8 个答案:

答案 0 :(得分:5)

您可以将两个嵌套的if折叠为一个:

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

第一个评估为false的文件阻止了第二个的执行,因此没有空引用异常。此行为通常称为“短路评估”:程序很快就会理解它可以跳过if,它会停止评估剩余部分。

答案 1 :(得分:3)

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

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

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

答案 2 :(得分:2)

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

 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) 
{
    //...
}

答案 3 :(得分:1)

你可以简单地合并一些if(),因为布尔运算有一个定义的顺序,它们的操作数被评估(从左到右):

而不是写这个:

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

你可以简单地使用它:

if (condition_a && condition_b)
     action();

确保您仍然先验证对象是否存在,然后再进行检查。

答案 4 :(得分:1)

通过将前两个if组合成一个并将属性选择放入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,了解为何可以将前两个if合并为一个。

答案 5 :(得分:1)

改进它并结合两个if,你可以尝试

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;
             }
         }
     } 
}

答案 6 :(得分:1)

我经常发现代码更具可读性而不是重复:

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 !
        }
    }
}

看一下条件验证后我添加的回报:我认为你不需要继续迭代。

答案 7 :(得分:1)

如果是我,我会这样写:

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;
}

需要注意的关键事项:

连续两个if可以通过将其表达式加到&&来替换。例如:

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();