26

Following code read a piece data from given DataRow(modelValue) and parse it to a nullable DateTime instance.

Question: Please see the code sections under L1 & L2 where both are technically equal (If i am not making any schoolboy error). However, L1 works as expected but not L2. I am getting

there is no implicit conversion between null and datetime

when I execute the code under L2. Can someone advise me ?

        DateTime? CallBack;

        var callBackDate = modelValue["CallBack"] == DBNull.Value ? null : modelValue["CallBack"].ToString();
        //Parsing
        DateTime cdate;
        if (!DateTime.TryParse(callBackDate, out cdate))
            cdate = DateTime.MinValue;


        //L1
        if (cdate==DateTime.MinValue)
            CallBack = null;
        else
           CallBack = cdate.Date;

       //L2  
       CallBack = cdate == DateTime.MinValue?null:cdate.Date;
Liam
  • 27,717
  • 28
  • 128
  • 190
S.N
  • 4,910
  • 5
  • 31
  • 51
  • 1
    This has been asked before a lot, for example [here](http://stackoverflow.com/questions/75746/conditional-operator-assignment-with-nullablevalue-types). IMO, the cleanest workaround that still uses `?:` is `... ? default(DateTime?) : ...`. –  Dec 05 '13 at 11:29
  • The compiler fails to infer that the expression `cdate == DateTime.MinValue?null:cdate.Date` should return `DateTime?` instead of `DateTime` (because `cdate.Date` is `DateTime`). So, it tries to convert null to `DateTime`... and fails. – Theraot Dec 05 '13 at 11:42

4 Answers4

40

You need to tell the compiler that the null should be treated as DateTime?. Otherwise the compiler doesn't know what type null is.

CallBack = cdate == DateTime.MinValue ? (DateTime?)null : cdate.Date;

Jakub Konecki
  • 45,581
  • 7
  • 87
  • 126
  • "Otherwise the compiler doesn't know what type null is." That's not the problem here. The same expression would have worked if the third operand was a reference type or a nullable type, instead of a non-nullable value type. The problem is that there is no implicit conversion between null and `DateTime`. – dcastro Dec 05 '13 at 11:37
  • @Jakub Konecki, Please see the code sections L1 & L2 where both are technically equal and i presume csc.exe use same style of compilation for those two sections. Also, if i go with your result then how DateTime? dt=null works fine (whether you declare it within a method or as a field) ? We don't do any explicit casting here right. – S.N Dec 05 '13 at 11:41
  • @Nair the compiler is trying to cast `null` to `DateTime`, not to `DateTime?`. Yes it can cast `null` to `DateTime?`. – Theraot Dec 05 '13 at 11:44
  • @Nair see my answer, where I explain why the compiler is not able to evaluate the expression. – dcastro Dec 05 '13 at 11:48
33
(Z) ? X : Y

The ternary operator requires that an implicit conversion exists from the second operand (X) to the third operand (Y), or from Y to X.

Since null cannot be implicitly converted to DateTime, nor DateTime to null, the expression cannot be evaluated. More on this: Type inference woes by Eric Lippert.

You have to cast null to DateTime?. By doing so, X will be of type DateTime? and Y will be of type DateTime. Since there is an implicit conversion from DateTime to DateTime?, the expression can be evaluated, and it will return a value of type DateTime?.

Alternatively, and following the same logic, you could also cast the third operand Y to DateTime?.

dcastro
  • 66,540
  • 21
  • 145
  • 155
5

Why don't you use the DataRow.Field extension method which supports nullable types in the first place?

DateTime? CallBack = modelValue.Field<DateTime?>("CallBack");

But since you actually have a string column you need to parse it first:

DateTime? CallBack = null;
string callBackDate = modelValue.Field<string>("CallBack");
if(!string.IsNullOrWhiteSpace(callBackDate))
{
    DateTime cdate;
    if(DateTime.TryParse(callBackDate, out cdate))
        CallBack = cdate;
}

That's all.

Tim Schmelter
  • 450,073
  • 74
  • 686
  • 939
1

You could do the following:

        DateTime aDateTime = DateTime.MinValue;
        DateTime? aNullableDateTime = aDateTime == DateTime.MinValue ? null : new DateTime?(aDateTime.Date);

which uses the Nullable(Of T) structure.

lex87
  • 1,276
  • 1
  • 15
  • 33