I recently started picking out different topics that I like to learn more about. One such thing I wanted to have a closer look at is βNullable value types in C#β.
We first need to understand the βwhyβ behind nullable value types.
Letβs have a look at this class:
public class User
{
public string Name { get; set; }
public int DaysSinceLastLogin { get; set; }
public DateTime RegistrationTimestamp { get; set; }
public User()
{
DaysSinceLastLogin = -1; // Magic Number
RegistrationTimestamp = DateTime.MinValue; // Magic Number
}
}
When designing a class like this, we often come across situations where we want to default a value type to a null
or tell the program that thereβs no actual value set.
In the above example, since RegistrationTimestamp
and DaysSinceLastLogin
are value types, we canβt represent that an actual value exists, we need to default them to the magic numbers we chose. Two major drawbacks of this approach are, we wouldnβt know what the actual magic numbers represent and if we decide to change the value we need to do some plumbing to get around it.
For a much cleaner implementation we can make use of C#βs out of the box Nullable Value Types.
Definition of the Nullable Value Types
The MSDN definition goes as follows:
A nullable value type T? represents all values of its underlying value type T and additional null value.
Letβs think of DaysSinceLastLogin
from the above example. Its type is Int32 which spans from -2,147,483,648 to 2,147,483,647. Obviously, in our context, we donβt need negative numbers to represent how many days have elapsed since the last login of the user (we could have used uint
instead, but letβs not get bogged down with such details). For the sake of the argument, letβs look at how to can convert it to a Nullable value Type.
What this does is, essentially, it wraps our value type of int
in a Nullable struct; which allows us to assign it an integer value or a null
Refactoring our code with Magic Numbers
public class User
{
public string Name { get; set; }
public Nullable<int> DaysSinceLastLogin { get; set; }
public Nullable<DateTime> RegistrationTimestamp { get; set; }
public User()
{
DaysSinceLastLogin = null;
RegistrationTimestamp = null;
}
}
Now we can simply assign null
s to our DaysSinceLastLogin
and RegistrationTimestamp
. But, C# is known for its nice syntactic sugar. Letβs sugarcoat it like so:
public class User
{
public string Name { get; set; }
public int? DaysSinceLastLogin { get; set; }
public DateTime? RegistrationTimestamp { get; set; }
}
This is beautiful, and behind the scenes, it still wraps in a Nullable<T>
struct. Another good thing is that now we donβt need to explicitly specify null
to DaysSinceLastLogin
and RegistrationTimestamp
. We all know that null
s are a billion dollar mistake, but still, could have been worse π
Convenience properties and methods of Nullable
-
.HasValue
-true
if it has a value; false if null -
.Value
- Gives us the underlying value. However, this will throw anInvalidOperationException
if you try to access a value whose.Value
property isfalse
-
.GetValueOrDefault()
- Underlying value or default. Eg: for an integer whose value has not been set, will return0
-.GetValueOrDefault(T)
- Value or a specified default value.
In my next post, we will look at how we can access and check for null values in C#. Until then βοΈ
Top comments (0)