m1m1k
m1m1k

Reputation: 1445

Boolean "Or" with right-hand ternary expression doesn't short-circuit

In general, the short-circuit behavior of the logical "or" operator || ignores the right side of the expression if the left side evaluates to true. Apparently, using a ternary as the right-hand expression is an exception to this rule:

List<int> foo = null;
bool bar = false;

if (foo == null || bar != true ? foo.Count == 0 : true)
{
    // ...Conditional code...
}

This code throws a NullReferenceException on foo.Count because foo is null. And naturally, the boolean logic allows for this. But, if foo is null, you would expect that the "or" would short-circuit and not even evaluate the right side of the expression, but it still does, and so it throws the exception.

Is this a bug in my code or in the C# compiler? Is there a part of the C# specification that handles this case?

Upvotes: 0

Views: 647

Answers (4)

Sergey Berezovskiy
Sergey Berezovskiy

Reputation: 236308

According to Operator precedence and associativity conditional operator ?: has lowest priority. Thus it will be executed last. Like this:

(foo == null || bar != true) ? foo.Count == 0 : true

Upvotes: 2

Marius Schulz
Marius Schulz

Reputation: 16470

Imagine parentheses around the condition you're checking:

if ((foo == null || bar != true) ? foo.Count == 0 : true)
{

}

Thus, if foo is null, you're attempting to read foo.Count, which will naturally result in a NullReferenceException.

Upvotes: 3

Zbigniew
Zbigniew

Reputation: 27614

No, it works correctly, refer to operator precedence. || will be evaluated before ?:

So it firstly evaluates foo == null || bar != true and then ? foo.Count == 0 : true, so it's more like:

if ((foo == null || bar != true) ? foo.Count == 0 : true)
{

}

If you want to use short-circut here then it should be:

if (foo == null || (bar != true ? foo.Count == 0 : true))
{

}

Upvotes: 11

Justin Niessner
Justin Niessner

Reputation: 245479

That's because your statement isn't being evaluated as you expect.

You need some extra parenthesis:

if(foo == null || (bar != true ? foo.Count == 0 : true))

The way it's written now is equivalent to (due to operator precedence):

if((foo == null || bar != true) ? foo.Count == 0 : true)    

Upvotes: 18

Related Questions