So briefly, lets look at a few of the defining features of value types:

  • Allocated on the stack.
  • Have a default value (newobj not required).
  • Are typically pretty small (integer types, booleans etc)
  • Are copied by value by default.

The reason the runtime distinguishes between value types and reference types is performance. A value type is much faster to work with because the runtime doesn’t have the dereference them to get at the data.

Now you may be wondering why they don’t make everything a value type – well, the act of doing that would make them slow. The stack is a small efficient pocket of memory that the runtime can get at quickly. If you put everything on the stack it would become a heap!

Boxing and Unboxing

It is possible for a value type to live on the heap, and the processing of taking it on and off of the heap is called boxing and unboxing respectively. Boxing and unboxing is pretty expensive, but it was hard to avoid without a lot of work in .NET 1.x because the default collection classes really only dealt with objects – if you wanted to be more efficient you had to build your own collection and down your own internal array resizing etc.

Nullable Types

I said that value types always have a default value, and thats true, but in .NET 2.0 they introduced a new generic type called Nullable<T> which basically allows us to set a value type to a null value. This kind of thing would be most valuable on the data path for an application where the underlying application database supports the concept of nullability for tradtional .NET value types.

C# 2.0 provides us with a shortcut syntax where we can just append a ? to a value type variable definition to say it is nullable, and we can also use the ?? operator to allow us to set a default value if the variable being worked on happens to be set to null.

When it comes to evaluating expressions with nullable types the general rule is that if one of the operands is null, the result is null. However, when it comes to working with the & and | operators and a nullabel boolean the story is a little bit different.

This MSDN reference has a good table to look at this specifically – but in general the logic conforms to how we would expect SQL to behave.