Reputation: 1445
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
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
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
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
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