C# Conditional Operator – Type Result with Ternary Operator

c++conditional-operatornullableternary-operatortype-conversion

I am trying to use the conditional operator, but I am getting hung up on the type it thinks the result should be.

Below is an example that I have contrived to show the issue I am having:

class Program
{
    public static void OutputDateTime(DateTime? datetime)
    {
        Console.WriteLine(datetime);
    }

    public static bool IsDateTimeHappy(DateTime datetime)
    {
        if (DateTime.Compare(datetime, DateTime.Parse("1/1")) == 0)
            return true;

        return false;
    }

    static void Main(string[] args)
    {
        DateTime myDateTime = DateTime.Now;
        OutputDateTime(IsDateTimeHappy(myDateTime) ? null : myDateTime);
        Console.ReadLine();                        ^
    }                                              |
}                                                  |
// This line has the compile issue  ---------------+

On the line indicated above, I get the following compile error:

Type of conditional expression cannot be determined because there is no implicit conversion between '< null >' and 'System.DateTime'

I am confused because the parameter is a nullable type (DateTime?). Why does it need to convert at all? If it is null then use that, if it is a date time then use that.

I was under the impression that:

condition ? first_expression : second_expression;

was the same as:

if (condition)
   first_expression;
else
   second_expression;

Clearly this is not the case. What is the reasoning behind this?

(NOTE: I know that if I make "myDateTime" a nullable DateTime then it will work. But why does it need it?

As I stated earlier this is a contrived example. In my real example "myDateTime" is a data mapped value that cannot be made nullable.)

Best Answer

The compiler does not infer the type of the result of the conditional operator from the usage of the result, but from the types of its arguments. The compiler fails when it sees this expression because it cannot deduce the type of the result:

IsDateTimeHappy(myDateTime) ? null : myDateTime;

Since null and DateTime are not compatible, you need to tell the compiler what the type should be. A cast should do the trick:

DateTime? x = IsDateTimeHappy(myDateTime) ? (DateTime?)null : myDateTime;
OutputDateTime(x);

Now the compiler will have no problems. You can also write the above on one line if you prefer (but I would probably not do this):

OutputDateTime(IsDateTimeHappy(myDateTime) ? (DateTime?)null : myDateTime);

Eric Lippert has a good answer that is also relevant here and goes into more details about how the compiler determines types.