c#中的Nullsafe导航



可能的重复:
C#中的安全导航算子
“如果对象为null,则为null;如果对象不为null,那么为object.member”

在我的XML处理项目中,我必须浏览chained属性以获得所需的值。例如CCD_ 1。并且该链中的任何对象都有可能为空。

我在谷歌上搜索了"c#中的NullSafe导航",发现了一些不错的文章。从一篇文章中,我得到了一个实现自定义扩展的想法。现在我有一个关于这个扩展的性能的问题。我有这3个解决方案。有人能建议我(就表现而言)采用哪一种最好吗?

  • 选项1(使用本文中解释的逻辑):

    //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;
    }
    
  • 选项3:

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

我肯定不会选择try-catch选项。这不仅是一种代码气味(异常驱动的开发),而且如果您担心性能,那么异常处理不是解决问题的方法。

我不太明白第二种选择。您是否必须将其放在要访问Value属性的任何位置?或者是在扩展方法中。

选项一看起来最干净。

关于性能:我认为您不会发现选项1和选项2之间有太大的差异,但您可以在一个小型控制台项目中尝试一下。只需运行第一个和第二个选项,例如1000次,然后计算所需的时间。不是精确的科学,但通常足以衡量绩效差异。

我猜你不会看到太大的区别。我觉得你在练习微观优化。除非你要在一个真正重要的系统上运行,否则选择对你来说最优雅的解决方案。

我支持选项#2。

选项#1:如果Obj1为null,则它将继续每次检查Obj2、Obj3、Obj4和Obj5是否为null!至少对于Option#2,只要它发现Obj1为null,就不会检查if语句的其余部分,这意味着处理周期更少。

选项#3当然不好。捕捉异常是一项开销,如果你反复遍历数千个节点,你会感觉到它——更不用说气味了。

我担心的是你可能问错了问题。你说你在使用XML,那么这些对象实际上就是元素,对吧?

也许,如果您用不同的措辞表达问题,并提供更多关于XML文档结构的信息,我们可以编写一个Linq查询来提取值,而不需要所有硬编码的null检查(以及我假设您也在使用的循环)。

你确定选项2这么糟糕吗?只要catch块不向调用者抛出任何异常,try/catch块就不会影响性能(异常抛出机制是性能消耗者)。

这里有一个引文:

寻找和设计异常严重的代码可能导致表现不错的胜利。请记住这与try/catch无关块:只有当实际的异常被抛出。你可以使用尽可能多的try/catch块你想要的。使用异常无偿是你失去的地方表演例如,您应该远离使用控制流的异常。

取自http://msdn.microsoft.com/en-us/library/ms973839.aspx

显然,只要你在链中的某个地方发现了一个null,设计#3就可以防止继续进行评估,就像设计#1一样,也可以防止像设计#2那样编写笨拙的代码。

我认为尝试/捕获的设计值得考虑。。。

我会使用一个节点结构,这样你就可以做到这一点:

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;

相关内容

  • 没有找到相关文章

最新更新