Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Casting with conditional/ternary ("?:") operator

I have this extract of C# source code:

object valueFromDatabase; decimal result; valueFromDatabase = DBNull.Value;  result = (decimal)(valueFromDatabase != DBNull.Value ? valueFromDatabase : 0); result = (valueFromDatabase != DBNull.Value ? (decimal)valueFromDatabase : (decimal)0); 

The first result evaluation throws an InvalidCastException whereas the second one does not. What is the difference between these two?

like image 408
Ioannis Avatar asked Jul 23 '09 13:07

Ioannis


People also ask

Which is called ternary operator ?: && ===?

The conditional operator (? :) is a ternary operator (it takes three operands).

What is ?: In JavaScript?

The conditional (ternary) operator is the only JavaScript operator that takes three operands: a condition followed by a question mark ( ? ), then an expression to execute if the condition is truthy followed by a colon ( : ), and finally the expression to execute if the condition is falsy.

Is conditional operator same as ternary operator?

The ternary operator takes three operands, hence, the name ternary operator. It is also known as a conditional operator.

Can ternary operator have two conditions?

In the above syntax, we have tested 2 conditions in a single statement using the ternary operator. In the syntax, if condition1 is incorrect then Expression3 will be executed else if condition1 is correct then the output depends on the condition2. If condition2 is correct, then the output is Expression1.


1 Answers

UPDATE: This question was the subject of my blog on May 27th 2010. Thanks for the great question!

There are a great many very confusing answers here. Let me try to precisely answer your question. Let's simplify this down:

object value = whatever; bool condition = something; decimal result = (decimal)(condition ? value : 0); 

How does the compiler interpret the last line? The problem faced by the compiler is that the type of the conditional expression must be consistent for both branches; the language rules do not allow you to return object on one branch and int on the other. The choices are object and int. Every int is convertible to object but not every object is convertible to int, so the compiler chooses object. Therefore this is the same as

decimal result = (decimal)(condition ? (object)value : (object)0); 

Therefore the zero returned is a boxed int.

You then unbox the int to decimal. It is illegal to unbox a boxed int to decimal. For the reasons why, see my blog article on that subject:

Representation and Identity

Basically, your problem is that you're acting as though the cast to decimal were distributed, like this:

decimal result = condition ? (decimal)value : (decimal)0; 

But as we've seen, that is not what

decimal result = (decimal)(condition ? value : 0); 

means. That means "make both alternatives into objects and then unbox the resulting object".

like image 76
Eric Lippert Avatar answered Sep 23 '22 18:09

Eric Lippert