Nullable types (basics)
You have most likely come across such code:
int? i = 5;
By using “int?”, the integer which usually is a value type, becomes a nullable type. More specifically variable “i” is an instance of System.Nullable<T>. It can hold all values of an integer plus the null value. Nevertheless it behaves more or less like an integer. A nullable type can hold the value null, but not be itself null. Therefore you can still use the variable “i” even though you assign null to it.
Nullable types are very useful when using databases. Database booleans may not be initialized. The System.Nullable<bool> can replicate that properly by allowing 3 values: true, false and null.
static void Main(string[] args) { int? i = 5; Console.WriteLine(i.ToString()); i = null; // important: we assign a null value, we do not assign null to the variable Console.WriteLine("null value ToString(): " + i.ToString()); // the variable itself is not null, no exception Console.WriteLine("no exception thrown!"); //string s = null; //Console.WriteLine(s.ToString()); // throws a NullReferenceException as expected Console.WriteLine(i.HasValue ? "variable i has a value" : "variable i has no value"); i = 7; Console.WriteLine(i.HasValue ? "value of variable i is " + i : "variable i has no value"); i = null; Console.WriteLine("default value is: " + i.GetValueOrDefault()); // i.GetValueOrDefault() returns a value type (=integer) //Console.WriteLine("the integer value is: " + i.Value); // throws an exception, null cannot be unboxed i = 1; int b = 2; Console.WriteLine(b + i + 3); // no problem using operators Console.WriteLine(i.Value); Console.ReadLine(); } //
example output:
5
null value ToString():
no exception thrown!
variable i has no value
value of variable i is 7
default value is: 0
6
A nullable type can only be created for value types. Reference types can hold null already, there is no need for a nullable reference type. The syntax T? is shorthand for Nullable<T>, where T is a value type. The two variations are interchangeable. You can also use the operators == and != eg. if (i == null) i = 1;
In fact the nullable class is not a class. It is a struct. And this explains a lot. A struct is a value type. If supported you do not need the new keyword to create an instance (custom structs do need the new keyword). And when you assign the nullable (=struct) to another variable then you create a copy of that instance. You do not simply copy a reference, which would be much faster. Parameters and locals are created on the stack, members on the heap. As we are talking about value types, we now understand why variables themselves cannot be null. They can hold the value null though (see the following example code). Classes are more complex, you intent to modify them during their use. In contrast structs are best suited for small data which is not intended to be modified after the struct is created.
The nullable struct could look like this:
struct Nullable<T> where T : struct { private readonly bool _HasValue; private readonly T _Value; public Nullable(T xValue) { _HasValue = true; _Value = xValue; } // constructor public bool HasValue { get { return _HasValue; } } // public T Value { get { if (_HasValue) return _Value; throw new ArgumentException(); } } // public T GetValueOrDefault() { return _Value; } // } // struct
The struct “struct Nullable<T> where T : struct {}” is defined with “where T : struct”. This means the argument T has to be a value type (except a nullable, you cannot create nullables of nullables).
We will take a closer look at the “where T:” in the next post.
Posted on December 31, 2013, in Advanced, Basic, C#, Generics, Nullables and tagged C#, C-sharp, generics, null, nullable, nullable type, reference type, value type, where T. Bookmark the permalink. 1 Comment.
Pingback: Generic types (part 1, basics, advanced) | C# Hardcore Programming