ICanHazValue?
There seems to be some debate in the .NET community about using nullable value types. Here are some examples of declaring nullable value types.
Nullable<int> count;
DateTime? occurred; // short-hand for Nullable<DateTime>
But, what’s the best way to check whether such a nullable value type is currently null (ie: empty)? This is the debate!
The generic Nullable<T> struct, which is used to make any value type nullable, has a HasValue property, answering our question.
int? count = GetCount();
DateTime? occurred = GetDateOccurred();
bool hasCount = count.HasValue;
bool hasOccurred = occurred.HasValue;
But, you can also compare it to null, just as you would with any (nullable) reference type.
int? count = GetCount();
DateTime? occurred = GetDateOccurred();
Address address = GetAddress(); // reference types are nullablebool hasCount = count != null;
bool hasOccurred = occurred != null;
bool hasAddress = address != null;
Hmm…look at how consistent that is! I like to treat all nullable types the same. To me, “nullable” means “might be null”. So before I can use it, I need to make sure it is not null. My [pseudocode] pattern is:
if (object is not null)
{
safely use object;
}
So, in practice, doing this…
DateTime? d = GetDate(); // a nullable value type
if (d != null)
{
Show(d.Value);
}
is consistent with doing this…
Person p = GetPerson(); // reference types already nullable
if (p != null)
{
Show(p.Name);
}
Why use a special HasValue check when you can use a consistent pattern for all nullable types? Just because one is a nullable reference type and one is a nullable value type? For years, we’ve compared things to null before we use them, not because they are reference types, but because they might be null (because they are null-able).
It also seems natural after declaring that I want something to be nullable, to then compare it to, wait for it… null, versus calling HasValue which doesn’t even have the word “null” in it! I guess things would be different if the wrapper was actually called something like ICanHazValue<T>.
ICanHazValue<int> count = GetCount();
if (count.HasValue)
{
total += count.Value;
}
One more thing to consider: C# 8 supports nullable reference types. That allows code like this…
Person? p = GetPerson(); // explicitly nullable reference type
if (p != null) // note HasValue isn't even an option!
{
Show(p.Name);
}
So, shouldn’t we get in the habit of doing this as well?
DateTime? d = GetDate(); // explicitly nullable value type
if (d != null)
{
Show(d.Value);
}