7

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
    }
    
Community
  • 1
  • 1
Nirmit Shah
  • 758
  • 4
  • 10
  • When it is not normal, that one of those obj objects is null, then it is perfectly OK to use try catch. Btw, just an idea that might or might not work, what if you make an extension that takes a params and just throw everything in there and implement a fast logic cascade logic there? – LueTm May 24 '11 at 07:02
  • @Arsen: The answer you provided is already closed as dup, and sub-answer is marked as dup as well. – abatishchev May 24 '11 at 07:03
  • @ArsenMkrt no. its not a duplicate of that post. I already went through that post, but its not discussing about performance. while my question is about performance. Thanks. – Nirmit Shah May 24 '11 at 07:09
  • @abatishchev, yes, this post is helpful. Unfortunately it didnt came with my Googeling. :) Thanks for mentioning. – Nirmit Shah May 24 '11 at 07:10
  • See [C# elegant way of reading a child property of an object](http://stackoverflow.com/questions/5744640/c-elegant-way-of-reading-a-child-property-of-an-object) – Danko Durbić May 24 '11 at 07:28
  • How sure are you that these properties are not null? If only invalid documents have null in those properties I'd go with the exception pattern, if there are valid documents with null properties you'll have to use the null testing stuff. Or just bypass the issue entirely by using dynamically typed xml libraries, linq-to-xml xpath,... – CodesInChaos May 24 '11 at 08:00

4 Answers4

3

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.

Peter
  • 13,733
  • 11
  • 75
  • 122
1

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).

MikeTeeVee
  • 18,543
  • 7
  • 76
  • 70
  • Option #1 won't throw an NRE. `obj1.IfNotNull(arg)` will be compiled as the static method call `Option1StaticClass.IfNotNull(obj1, arg)`. That's why when using Linq methods on a null collection you get an ArgumentNullException and not an NRE. – Patrick Huizinga May 24 '11 at 07:41
  • Thanks Patrick, you are correct. I updated my answer accordingly. – MikeTeeVee May 24 '11 at 07:54
1

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 :

Finding and designing away exception-heavy code can result in a decent perf win. Bear in mind that this has nothing to do with try/catch blocks: you only incur the cost when the actual exception is thrown. You can use as many try/catch blocks as you want. Using exceptions gratuitously is where you lose performance. For example, you should stay away from things like using exceptions for control flow.

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...

Ssithra
  • 710
  • 3
  • 8
0

I would used a node structure, so that you could do this:

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;
stiduck
  • 510
  • 4
  • 9