我有这种代码的和平。我必须检查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;
}
}
}
}
}
答案 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;
}
XPathSelectElement
在System.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();