Ternary operator behaviour inconsistency

C#CastingIntConditional OperatorShort

C# Problem Overview


Following expression is ok

short d = ("obj" == "obj" ) ? 1 : 2;

But when you use it like below, syntax error occurs

short d = (DateTime.Now == DateTime.Now) ? 1 : 2;

Cannot implicitly convert type 'int' to 'short'. An explicit conversion exists (are you missing a cast?)

Can anyone explain why this is so?

Is there a difference between comparing string-to-string and datetime-to-datetime in a ternary operator, why?

I would be grateful if you could help me.

C# Solutions


Solution 1 - C#

C# language specification, version 5, section 6.1.9:

> An implicit constant expression conversion permits the following conversions:

> - A constant-expression (§7.19) of type int can be converted to type sbyte, byte, short, ushort, uint, or ulong, provided the value of the constant-expression is within the range of the destination type.

Your first example is a constant expression, because it can be evaluated at compile time. But see section 7.19 for more details:

> Only the following constructs are permitted in constant expressions:

> - Literals (including the null literal).

[...]

> - The predefined +, –, *, /, %, <<, >>, &, |, ^, &&, ||, ==, !=, <, >, <=, and >= binary operators, provided each operand is of a type listed above. > - The ?: conditional operator.

Solution 2 - C#

I believe in the first case the compiler knows that the strings are equal at compile time and therefore optimizes the code to just:

short d = 1;

That works because 1 can be assigned to short variable.

In the second case optimization cannot happen because compiler cannot infer equality at compile time, so it leaves:

short d = (DateTime.Now == DateTime.Now) ? (long)1 : (long)2;

This will compile:

short d = (DateTime.Now == DateTime.Now) ? (short)1 : (short)2;

IL (LinqPad) for call short d = ("obj" == "obj" ) ? 1 : 2;:

IL_0001:  ldc.i4.1    
IL_0002:  stloc.0     // d

Solution 3 - C#

"obj" == "obj" can be resolved at compile time; compiler treats it as

short d = 1;

namespace ConsoleApplication1 {
  class Program {
    static void Main(string[] args) {
      short d = ("obj" == "obj") ? 1 : 2;
    }
  }
}

.method private hidebysig static void  Main(string[] args) cil managed
{
  .entrypoint
 // Code size       4 (0x4)
 .maxstack  1
 .locals init ([0] int16 d)
 IL_0000:  nop
 IL_0001:  ldc.i4.1
 IL_0002:  stloc.0
 IL_0003:  ret
 } // end of method Program::Main

DateTime.Now == DateTime.Now can't be resolved at compile time and throws an error.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionMehmet KasalakView Question on Stackoverflow
Solution 1 - C#Damien_The_UnbelieverView Answer on Stackoverflow
Solution 2 - C#Jakub KoneckiView Answer on Stackoverflow
Solution 3 - C#Ondrej SvejdarView Answer on Stackoverflow