Once again, in this series of posts I look at the parts of the .NET Framework that may seem trivial, but can help improve your code by making it easier to write and maintain. The index of all my past little wonders posts can be found here.
There are many times in .NET where we have an instance of a value type that we need to treat as optional. That is, we may want to consider its value as being supplied or missing.
The System.Nullable<T> structure in the .NET Framework can be used to represent these situations in a consistent and meaningful way.
Why Do We Use Nullable<T>?
With instances of reference types, you can easily denote an optional item by simply leaving the reference as null, but this isn’t really possible with a value type (that is, not directly), because the instance of a value type always has a value.
For example, if you had an Person class with some basic data:
1: public class Person
2: {
3: public string FirstName { get; set; }
4: public string LastName { get; set; }
5: public int YearsRetired { get; set; }
6:
7: // ...
8: }
We could have a person with no first name (Sting, Madonna, etc… or is that no last name?), simply by setting the string property FirstName to null:
1: aPerson.FirstName = null;
But in the case of YearsRetired, if the person hasn’t retired yet, we can’t set a simple int to null, because an int is a value type, which must always have a value (strictly speaking):
1: // compiler error
2: aPerson.YearsRetired = null;
That said, we could use a sentinel value (-1), or have a separate bool field (IsRetired) to say whether we should use this field or not, but these get messy and harder to maintain. Consider that if you use a sentinel value, everyone who uses this field must know what that value would be and to test for it.
Alternatively, if you use a bool field to tell you if the value field is usable, they aren’t encapsulated, so again there could be usage issues or consistency issues in naming, etc.
This is why Nullable<T> exists, to allow you to easily mark value type instances as optional (“nullable”) by providing a mechanism that gives values types something like null semantics in an encapsulated and uniform way.
In this way, anyone who looks at your interface and sees Nullable<int> (can also be abbreviated int?) will know how to test whether it has a valid value or not.
How the Nullable<T> struct Works
When you have a Nullable<T> wrapped type in the .NET Framework, it doesn’t give you a reference which you can make null. It actually is a simple struct (value type) that wraps your value type. This is an important distinction because it clears up some common misconceptions on what the Nullable<T> type does and does not do.
For example, let’s say you have:
1: // or int? for short…
2: Nullable<int> yearsRetired = null;
What really is yearsRetired? Is it a reference that points to nothing? No, it’s actually an instance of a value type with two fields: HasValue, and Value. Note: for you C++ boost library users out there, this is much like how boost::optional<T> works.
Read more: James Michael Hare
QR: