C# 中的 Nullsafe 导航
可能的重复:
C# 中的安全导航运算符?
快捷方式“如果对象为空,则为 null,如果对象不为空,则为 object.member”
在我的 XML 处理项目中,我必须浏览链式属性才能获取所需的值。例如,obj1.obj2.obj3.obj4.obj....值
。并且该链中的任何对象都可能为空。
我在 google 上搜索“C# 中的 NullSafe Navigation”并找到了一些不错的文章。从其中一篇帖子中,我得到了实现自定义扩展的想法。 现在我对这个扩展的性能有疑问。 我有这3个解决方案。谁能建议我采用哪一种最好(就性能而言)?
选项1(使用本文解释的逻辑):
//自定义扩展方法 公共静态 TOutput IfNotNull
(this TInput x, Func f) 其中 TInput :类 其中 TOutput :类 { 返回 x == null ?空:f(x); } //使用自定义扩展方法——非常简洁干净..但是性能怎么样? 字符串 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——可能是正确的方法? 如果(obj1!= null && obj1.obj2 != null && obj1.obj2.obj3 != null && obj1.obj2.obj3.obj4 != null && obj1.obj2.obj3.obj4.obj5!= null) { 字符串 x = obj1.obj2.obj3.obnj4.obj5.Value; }
选项3:
//with try-catch..具有最低的圈复杂度,但不是正确的方法。 尝试 { 字符串 x = obj1.obj2.obj3.obnj4.obj5.Value; } 捕获(NullReferenceException ne) { //忽略异常 }
Possible Duplicates:
Safe Navigation Operator in C#?
Shortcut for “null if object is null, or object.member if object is not null”
in my XML processing project, i have to navigate through chained property to get the desired value. e.g, obj1.obj2.obj3.obj4.obj....Value
. and it is quit possible that any of the object in this chain is null.
I googled for "NullSafe Navigation in c#" and found some nice articles. From one of the Post, I got an idea to implement Custom Extension.
Now I have a question regarding the performance about this extension.
I have these 3 solution. can anyone suggest me which one is the best to adopt (in terms of performance)?
Option1 (using 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);
Option2:
//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; }
Option3:
//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 }
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
我绝对不会选择 try-catch 选项。这不仅是一种代码味道(异常驱动开发),而且如果您担心性能,异常处理也不是正确的选择。
我不太明白第二个选项。您是否必须将其放在您想要访问 Value 属性的任何地方?或者是在扩展方法中。
选项一看起来最干净。
关于性能:我认为您不会发现选项 1 和 2 之间有很大差异,但您可以在一个小型控制台项目中尝试一下。只需运行第一个和第二个选项(例如 1000 次)并计算所需的时间。不是精确的科学,但通常足以衡量性能差异。
我猜你不会看到很大的区别。我想你正在练习 微观优化。除非您要在一个确实很重要的系统上运行,否则请采用对您来说最优雅的解决方案。
I'd definitely not go with the try-catch option. Not only is this a code-smell (exception driven development), but if you're worried about performance, exception handling is not the way to go.
I don't quite understand the second option. Would you have to put that everywhere you want to access the Value property? Or is that in an extension method.
Option one looks the cleanest.
About performance: I don't think you'll find big differences between option 1 and 2, but you could try it out, in a small Console Project. Just run the first and the second option, say, 1000 times and calculate the time it takes. Not exact science, but usually good enough to measure performance differences.
I'm guessing you won't see a very big difference. I'm thinking you're practicing micro-optimization. Unless you're going to run on a system where this really is important, go with the solution that seems most elegant to you.
我支持选项#2。
选项#1:如果 Obj1 为 null,则每次都会继续检查 Obj2、Obj3、Obj4 和 Obj5 是否为 null!至少对于选项 #2,一旦发现 Obj1 为 null,它就不会费心检查 if 语句的其余部分 - 这意味着更少的处理周期。
选项#3 当然是不好的。捕获异常是有开销的,如果你反复遍历数千个节点,你就会感觉到它 - 别介意气味。
我担心的是你可能问错了问题。如果您声明您正在使用 XML,那么这些对象实际上就是元素,对吗?
也许如果您以不同的方式表达您的问题并提供有关 XML 文档结构的更多信息,我们可以编写一个 Linq 查询来提取值,而无需所有硬编码的空检查(以及我假设您也在使用的循环)。
I'm for option #2.
Option #1: If Obj1 is null, then it will continue to check for null for Obj2, Obj3, Obj4, and Obj5 every time! At least with Option #2, as soon as it finds that Obj1 is null, it doesn't bother checking the rest of the if statement - and that means less processing cycles.
Option #3 is of course bad. Catching exceptions is overhead, and if you're recurisely going through thousands of nodes, you're gonna feel it - never mind the smell.
My concern is you might be asking the wrong question. You state you're using XML, then these Objects are really Elements, right?
Maybe if you phrased your question differently and gave more information about the XML document structure, we could write an Linq query to pull the value without all the hard-coded null checks (and loops that I'm assuming you're also using).
您确定选项 2 如此糟糕吗?
只要catch块不向调用者抛出任何异常(这是异常抛出机制,即性能吞噬者),try/catch块就不会影响性能。
这是一个引文:
摘自http://msdn.microsoft.com/en-us/library/ms973839 .aspx
显然,设计 #3 会阻止在像设计 #1 那样的链中某处发现 null 的情况下继续进行评估,并且还可以防止像设计 #2 那样编写笨拙的代码。
我认为 try/catch 设计值得考虑......
Are you so sure that Option 2 is so bad ?
A try/catch block doesn't affect the performance as long as the catch block doesn't throw any exception to the caller (it is the exception throwing mechanism which is performance eater).
Here is a citation :
taken from http://msdn.microsoft.com/en-us/library/ms973839.aspx
Obviously design #3 prevents to go on with evaluating as long as you found a null somewhere in the chain like design #1, and also prevents from a heavy awkward code writing like design #2.
I think the try/catch design is worth considering...
我会使用节点结构,这样你就可以这样做:
I would used a node structure, so that you could do this: