0

I have the following objects:

class Parent
{
    public Child Child { get; set; }
}

class Child
{
    public string Type { get; set; }
    public int Value { get; set; }
}

Why does the following code throw a NullReferenceException?

var value = parent.Child != null && 
            parent.Child.Type == "test" 
                ? parent.Child.Value == 1 
                : parent.Child.Value == 2;

I would think the null-check would block the second part of the conditional from executing. However the following code works:

var value = (parent.Child != null) && 
            (parent.Child.Type == "test" 
                ? parent.Child.Value == 1 
                : parent.Child.Value == 2);

So I think some operator precedence is at fault here...

Lodewijk
  • 2,380
  • 4
  • 25
  • 40
  • 1
    Why wouldn't it throw that exception? – ProgrammingLlama Sep 23 '19 at 15:10
  • 2
    That code doesn't even compile? The two return values are different, one returns a bool and the other an int? – andyb952 Sep 23 '19 at 15:13
  • @andyb952 Considering how the ternary operator is used, I assume it's a typo and the second is meant to be `==` rather than `=`. – ProgrammingLlama Sep 23 '19 at 15:15
  • 1
    First code could be rewritten `(parent.Child != null && parent.Child.Type == "test") ? ...` Check John answer for more details – Cid Sep 23 '19 at 15:18
  • @andyb952 it was a type as John suggested – Lodewijk Sep 24 '19 at 06:47
  • 1
    _"I think some operator precedence is at fault here"_ -- Indeed. But if you already think that, you don't need to ask a question. There's [a documentation page for that](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/#operator-precedence). To reinforce the general idea, there's this statement from the first marked duplicate: [_"you should always assume it's your fault"_](http://www.codinghorror.com/blog/2008/03/the-first-rule-of-programming-its-always-your-fault.html). – Peter Duniho Oct 03 '19 at 01:05
  • Then the link to the documentation was the answer I was looking for. – Lodewijk Oct 03 '19 at 13:09

1 Answers1

2

Why wouldn't it throw a NullReferenceException?

var value = parent.Child != null && 
    parent.Child.Type == "test" 
        ? parent.Child.Value == 1 
        : parent.Child.Value == 2;

Let's rewrite your code with an interim variable:

bool condition = parent.Child != null && parent.Child.Type == "test";
var value = condition ? parent.Child.Value == 1 : parent.child.Value == 2;

And then with an if statement to make it even clearer:

bool value = false;
bool condition = parent.Child != null && parent.Child.Type == "test";
if (condition)
{
    value = parent.Child.Value == 1;
}
else
{
    vaue = parent.Child.Value == 2;
}

Your condition requires two things to be true: parent.Child isn't null, and parent.Child.Type is equal to "test".

If your condition is false, you use the "else" part of the ternary operator: parent.Child.Value == 2.

If your condition is false because parent.Child == null then you will be trying to access a null object's property in your else section, thus triggering a NullReferenceException.

As for why it's interpreted in this order, see this documentation page about C# operators and their precedence. As you can see, a && b has higher precedence than a ? b : c. a && b will therefore be executed before a ? b : c.

ProgrammingLlama
  • 36,677
  • 7
  • 67
  • 86