可能重复:
Safe Navigation Operator in C#?
Shortcut for “null if object is null, or object.member if object is not null”
在我的XML处理项目中,我必须浏览链式属性才能获得所需的值。例如,obj1.obj2.obj3.obj4.obj....Value
。并且可能会退出此链中的任何对象为空。
我搜索了“c#中的NullSafe导航”并找到了一些不错的文章。从其中一个Post,我有了实现自定义扩展的想法。 现在我对这个扩展的性能有疑问。 我有这3个解决方案。任何人都可以建议我采用哪一种(在性能方面)?
选项1(使用logic explained on this article):
//custom extension method
public static TOutput IfNotNull<TInput, TOutput>(this TInput x, Func<TInput, TOutput> f)
where TInput : class
where TOutput : class
{
return x == null ? null : f(x);
}
//with custom extension method -- Very neat & clean.. but what about performance?
string x = obj1
.IfNotNull(x => x.obj2)
.IfNotNull(x => x.obj3)
.IfNotNull(x => x.obj4)
.IfNotNull(x => x.obj5)
.IfNotNull(x => x.Value);
选项2:
//with NullCheck -- probably right way?
if(obj1 != null
&& obj1.obj2 != null
&& obj1.obj2.obj3 != null
&& obj1.obj2.obj3.obj4 != null
&& obj1.obj2.obj3.obj4.obj5 != null)
{
string x = obj1.obj2.obj3.obnj4.obj5.Value;
}
2选项:
//with try-catch.. With lowest cyclomatic complexity, but not a right approach.
try
{
string x = obj1.obj2.obj3.obnj4.obj5.Value;
}
catch(NullReferenceException ne)
{
//ignore exception
}
答案 0 :(得分:3)
我绝对不会选择try-catch选项。这不仅是代码嗅觉(异常驱动的开发),而且如果你担心性能,异常处理也不是可行的方法。
我不太了解第二种选择。您是否必须将它放在您想要访问Value属性的任何位置?或者是扩展方法。
选项一看起来最干净。
关于性能:我认为您不会发现选项1和2之间存在很大差异,但您可以在一个小型控制台项目中尝试一下。只需运行第一个和第二个选项,比如1000次并计算所需的时间。不是精确的科学,但通常足以衡量绩效差异。
我猜你不会看到很大的区别。我在想你正在练习micro-optimization。除非你要在一个真正重要的系统上运行,否则请选择对你来说最优雅的解决方案。
答案 1 :(得分:1)
我选择#2。
选项#1:如果Obj1为空,那么它每次都会继续为Obj2,Obj3,Obj4和Obj5检查是否为空!至少在选项#2中,一旦发现Obj1为空,它就不会检查if语句的其余部分 - 这意味着更少的处理周期。
选项#3当然很糟糕。捕获异常是开销,如果你复发地经历数千个节点,你会感觉到它 - 更别提气味。
我担心你可能会问错误的问题。你说你正在使用XML,那么这些对象真的是元素,对吗?
也许如果你以不同的方式表达你的问题并提供有关XML文档结构的更多信息,我们可以编写一个Linq查询来提取值而不需要所有硬编码的空值检查(并且我假设你也是循环使用)。
答案 2 :(得分:1)
您是否确定选项2如此糟糕? 只要catch块没有向调用者抛出任何异常(它是性能消耗的异常抛出机制),try / catch块不会影响性能。
这是一个引用:
寻找和设计 异常繁重的代码可能导致a 体面的胜利。请记住这一点 这与try / catch无关 块:你只会产生成本 抛出实际异常。您 可以使用尽可能多的try / catch块 你要。使用例外 无偿的是你失败的地方 性能。例如,你应该 远离使用的东西 控制流程的例外。
取自http://msdn.microsoft.com/en-us/library/ms973839.aspx
显然,设计#3可以防止继续进行评估,只要你在设计#1中的链中找到一个null,并且还可以防止像设计#2那样繁琐的代码编写。
我认为try / catch设计值得考虑......
答案 3 :(得分:0)
我会使用节点结构,这样你就可以这样做:
var hasNullValue = false;
var x = string.Empty;
var node = firstNode;
while (node.Child != null)
{
// On the first hit we set the null flag
// and break out of the loop
if (node.Value == null)
{
hasNullvalue = true;
break;
}
node = node.Child;
}
if (!hasNullValue)
x = node.Value;