Reputation: 257153
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);
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?
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!
I cross-checked with .NET Fiddle in case it's an artifact in my Visual Studio.
Upvotes: 1
Views: 310
Reputation: 3285
Probably the code analyzer is not sufficiently intelligent to conclude your date
and time
can never be null.
You can inform it of that fact by using the 'null forgiving' operator:
public static DateTime JoinNullableDateTime(DateTime? date, DateTime? time)
{
...
else
return date!.Value.Date.Add(time!.Value.TimeOfDay);
}
Upvotes: 2
Reputation: 314
Update your Visual studio to 2022.
2022 doesn't show any warning for nullable.
Download from this link
Upvotes: 0