I've found some code that runs afoul of the new nullable reference types in C# 8, saying i could be referencing a null, when i cannot figure out how it could possibly ever be null:
https://dotnetfiddle.net/AoEMzp
public static DateTime JoinNullableDateTime(DateTime? date, DateTime? time)
{
if ((date == null) && (time == null))
return DateTime.MinValue;
else if ((date != null) && (time == null))
return date.Value.Date;
else if ((date == null) && (time != null))
return DateTime.MinValue.Add(time.Value.TimeOfDay);
else
return date.Value.Date.Add(time.Value.TimeOfDay);
}
Both Visual Studio and .NET Fiddle return the warnings for the last line:
return date.Value.Date.Add(time.Value.TimeOfDay);
.NET Fiddle
Visual Studio
So my question is, can anyone give any examples of values for date and time that would cause a NullReferenceException in this code?
At the start, the possible combinations of null-ness are:
| date | time | Possible? |
|---|---|---|
| null | null | Yes |
| not-null | null | Yes |
| null | not-null | Yes |
| not-null | not-null | Yes |
if ((date == null) && (time == null))`
return DateTime.MinValue;
At this point the possible combinations of null-ness are:
| date | time | Possible? |
|---|---|---|
| null | null | No (because we returned) |
| not-null | null | Yes |
| null | not-null | Yes |
| not-null | not-null | Yes |
else if ((date != null) && (time == null))
return date.Value.Date;
At this point the possible combinations of null-ness are:
| date | time | Possible? |
|---|---|---|
| null | null | No (because we returned) |
| not-null | null | No (because we returned) |
| null | not-null | Yes |
| not-null | not-null | Yes |
else if ((date == null) && (time != null))
return DateTime.MinValue.Add(time.Value.TimeOfDay);
Finally the possible combinations of null-ness are:
| date | time | Possible? |
|---|---|---|
| null | null | No (because we returned) |
| not-null | null | No (because we returned) |
| null | not-null | No (because we returned) |
| not-null | not-null | Yes |
So at this point it is not possible for date nor time to be null. Both are guaranteed to be NOT NULL.
else
return date.Value.Date.Add(time.Value.TimeOfDay);
I cannot see any way in which either date or time could be null on the final line - yet there it is:
CS8629 Nullable value type may be null.
So what am i missing?
In fact the nulls go away even faster
After the first line
(date == null) && (time == null)
We know that it is still possible for one of them to be null - but not both. So then we hit the 2nd check:
(date != null) && (time == null)
Before this line we knew that only one was null. And now we've found the one that it was: it was time.
This means by the 3rd line it is impossible for date to be null. And yet i added a check anyway, because the compiler told me to, and the compiler is infallible. But i have the check anyway:
(date == null) && (time != null)
So the extra checking even on the third if was redundant. And certainly it is redundant on the 4th if. And yet there is the compiler.
What am i doing wrong?
I'm certain i could re-write the function into something harder to understand, so it doesn't confuse Roslyn. But this isn't about this function, it's about the pattern being used - and if this pattern has lurking NullReferenceExceptions: i want to know about it!
Bonus
I cross-checked with .NET Fiddle in case it's an artifact in my Visual Studio.

