James Michael Hare

...hare-brained ideas from the realm of software development...
posts - 136 , comments - 1091 , trackbacks - 0

My Links

News

Welcome to my blog! I'm a Sr. Software Development Engineer in Seattle, WA. I've been doing C++/C#/Java development for over 18 years, but have definitely learned that there is always more to learn!

All thoughts and opinions expressed in my blog and my comments are my own and do not represent the thoughts of my employer.

Blogs I Read

MCC Logo MVP Logo

Follow BlkRabbitCoder on Twitter

Tag Cloud

Archives

Post Categories

C#/.NET Little Wonders: The Nullable<T> struct

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 ValueNote: for you C++ boost library users out there, this is much like how boost::optional<T> works.

The HasValue field is a bool that tells you whether or not Value contains a valid value, and the Value field contains the value set by the user.  Also, to make sure that you use the type correctly, if you attempt to access Value directly when HasValue is false, you will get an InvalidOperationException.

So as you can see, this mimics the behavior of a reference type in some ways, but not others.  For example, you won’t save any space having an “empty” Nullable<BigHonkingStruct>.  The Value field still has the space for a BigHonkingStruct, it’s just inaccessible (that is, it always has a value, it just may not be a valid – i.e. user assigned -- value).

This may be confusing, because while you think you are setting a field to a null, it’s really just compiler magic.  For example, you can do this:

   1: int? yearsRetired = null;
   2:  
   3: if (yearsRetired == null)
   4: {
   5:     Console.WriteLine(“Active Employee”);
   6: }

But this is just syntactical sugar that actually just converts the usage of null to mimic calls against HasValue and Value:

   1: int? yearsRetired = default(int?);     // creates with HasValue = false, Value = default(int)
   2:  
   3: if (yearsRetired.HasValue == false)
   4: {
   5:     Console.WriteLine(“Active Employee”);
   6: }

So don’t be fooled into thinking Nullable<T> magically saves space for “null” instances of large value types.  In fact, if you have a struct so large that you are worried about wasted space, consider a class instead (see C# Fundamentals: The Differences between Struct and Class for more details).

Getting a Default Value

Many times while you are using a Nullable<T> instance, you may find yourself writing code like this:

   1: int cost = 0;
   2:  
   3: if (contractSize.HasValue)
   4: {
   5:     // you can do math on Nullable<int> directly, with caveats…
   6:     cost = contractSize * price;
   7: }
   8:  
Which you could shorten down using a conditional, of course:
   1: int cost = (contractSize.HasValue ? contractSize.Value : 100) * price;

That is, you want to use the value of a Nullable<T> in an expression, or a stand-in if the instance is “null”.  Either way so far, it looks a wee bit ugly, but there are a few ways we can clean this code up.

Nullable<T> has a method GetValueOrDefault() that allows you to retrieve the value if it exists, or the default specified if not.  It has two forms:

  • GetValueOrDefault()
    • Returns Value if HasValue is true, or default(T) if not.
  • GetValueOrDefault(T defaultValue)
    • Returns Value if HasValue is true, or defaultValue if not.

Thus, the code we wrote above could more concisely be written as:

   1: int cost = contractSize.GetValueOrDefault(100) * price;

Ah, much cleaner!  In addition, if you want the defaultValue to be whatever the default is for the given type, you can just call it without any parameter. 

   1: // these evaluate to same value, because 0 is default for int.
   2: int cost1 = contractSize.GetValueOrDefault(0) * price;
   3: int cost2 = contractSize.GetValueOrDefault() * price;  

Nullable<T> and the Null-coalescing operator

Another nice thing C# did in .NET 2.0 was to add a null-coalescing operator (??) to get the value of a reference type if non-null, or a stand-in value if null.  They also performed some syntactical candy to allow this to work with Nullable<T> as well.  Basically, this behaves very similarly to using GetValueOrDefault():

   1: Console.WriteLine(“ The contract size is: {0}”, contractSize ?? 100);

The main thing to note here is that ?? is very low on the operator precedence, so if instead you had typed this:

   1: // compiler error, thinks you are trying to ?? between string and int
   2: Console.WriteLine(“The contract size is: “ + contractSize ?? 100);

You’d get an error, because it first tries to concatenate the string and contractSize, which results in a string, and then attempts to null-coalesce a string with an int value, which is invalid.  That is, it thought you wanted this:

   1: // + has higher precedence than ??
   2: Console.WriteLine((“The contract size is: “ + contractSize) ?? 100);

So when you use ?? in an expression, make sure you surround it in parenthesis where appropriate to make sure it is performed in the order you really mean:

   1: Console.WriteLine(“The contract size is: “ + (contractSize ?? 100));

Nullable Math Doesn’t Always Add Up

Finally, there are some interesting results when you attempt to use an arithmetic or logical comparison operator overload on a Nullable<T> wrapping a T that has those operators.  That is, if you have:

   1: int? x = null;
   2:  
   3: if ((x * 5) < 100)
   4: {
   5:     // ...
   6: }
   7:  

What will the result be?  It turns out false because the operator * between null and 5 returns null, and null has no meaningful order so < returns false.  In essence, this is modeled to behave much like SQL expressions with null values.  The long and the short of the matter is that math with a null numeric type yields null, and an ordered logical comparison with a null yields false.

For more details, I have a post titled C#/.NET Little Pitfalls: Nullable Math Doesn’t Always Add Up which you can dig into for more information on why this happens.

Summary

The Nullable<T> is a handy structure that was created to give us a consistent way to handle “optional” instances of value types. Nullable<T> instances can be assigned to null or compared with null, which really is syntactical sugar which creates a default instance or checks the HasValue property respectively. 

In addition, you can use the GetValueOrDefault() method or the null-coalescing operator (??) to query the value, or provide a substitute if the value was never set.

Print | posted on Thursday, July 12, 2012 6:10 PM | Filed Under [ My Blog C# Software .NET Little Wonders ]

Feedback

Gravatar

# re: C#/.NET Little Wondres: The Nullable<T> struct

Wonderful post!This is very useful to many readers like me.Being a student, I am requiring myself to read articles more often and your writing just caught my interest.Thank you

7/13/2012 7:01 AM | Lisa Donaho
Gravatar

# re: C#/.NET Little Wondres: The Nullable<T> struct

@Lisa: Thanks, glad it helps!
7/13/2012 8:04 AM | James Michael Hare
Gravatar

# re: C#/.NET Little Wondres: The Nullable<T> struct

That's two beer points just for pointing out GetValueOrDefault (I can't conceive of how I missed that one)...if I had a nickel for every time I've written .HasValue ? ... : ...
7/13/2012 8:20 AM | Brian Hartung
Gravatar

# re: C#/.NET Little Wondres: The Nullable<T> struct

James, thanks that you are writting great blogs that are understandable no only by C# experts, but for begginers also.

Before I've read this post I were not aware that int? is actually Nullable<int> and about method:
contractSize.GetValueOrDefault(10)
7/13/2012 5:09 PM | Dmitry
Gravatar

# re: C#/.NET Little Wondres: The Nullable<T> struct

Fantastic post. [There is a typ in the post title : Wondres?]
7/16/2012 10:02 AM | Srikanth
Gravatar

# re: C#/.NET Little Wonders: The Nullable<T> struct

@Srikanth: Thanks! And thanks for pointing out the typo on Wonders (Wondres), fixed it.
7/16/2012 10:27 AM | James Michael Hare
Gravatar

# re: C#/.NET Little Wonders: The Nullable<T> struct

If i'm correct, the line "int cost = 0" should be changed for "int cost = 100*price"
7/17/2012 9:53 AM | Wizou
Gravatar

# re: C#/.NET Little Wonders: The Nullable<T> struct

@Wizou: Yep, that'll teach me to modify a code example mid-thought...
7/17/2012 11:38 AM | James Michael Hare
Gravatar

# re: C#/.NET Little Wonders: The Nullable<T> struct

LOL. I wrote something similar to GetValueOrDefault() one time. I guess I need to make a habit to check documentation more often.
7/19/2012 5:58 PM | Joshua
Gravatar

# re: C#/.NET Little Wonders: The Nullable<T> struct

It was very useful for me. Keep sharing such ideas. This was actually what I was looking for, and I am glad to came here!
7/19/2012 11:40 PM | sales training
Gravatar

# re: C#/.NET Little Wonders: The Nullable<T> struct

Great post! Very well written!
7/20/2012 9:34 AM | Tom
Gravatar

# how to learn c#

thank to admin because there are lot of programing language which is very useful for me to learn to programing
7/24/2012 11:31 AM | serajul
Post A Comment
Title:
Name:
Email:
Comment:
Verification:
 
 

Powered by: