Nullable Types
Is a instance of the System.Nullable
Value type cannot be assigned a null value eg int i = null, but with Nullable
Example
Nullable<int> intValue = 5 ?? null; — can have interger value or null
Nullable<bool> boolValue = true ?? null — can have true, false or null
Nullable<double> doubleVal = 2.14 ?? null — can have double or null
Nullable<char> charVal = ‘a’ ?? null — can have char or null
Nullable<int>[] arr = new Nullable<int>[10]
Shorthand syntax
‘?’
Nullable<int> i = null; //becomes int? i = null //is a lightweight immutable structure.
public struct Nullable<T> where T : struct { public bool HasVaalue { get; } public T Value { get; } //rest of the implementation }
Attempting to retrieve Value when HasValue is false throws an InvalidOperationException.
Constructors
Nullable<T>(T) – initialize a new instance
Declaration
Nullable<int> i = null;
Properties
HasValue – boolean return whether Nullable
int? val = null; Console.WriteLine(val.HasValue); //false val = 1; Console.WriteLine(val.HasValue);//true
Alternative way of doing this will be using the operator:
int? y = 10; if(y != null) Console.WriteLine("Has Value");
Value – gets the value of the current Nullable<T> object
Console.WriteLine(val.Value);//1 Console.WriteLine(val);// 1 if(val == 1) Console.WriteLine("True");
Methods
Equals(Object)
Indicates whether the current Nullable<T> object is equal to a specified object
int? nullInt1 = 100; int? nullInt2 = 200; object myObj; if(nullInt1.Equals(nullInt2)) { Console.WriteLine("Both are equal"); }
GetHashCode()
Retrives the hash code of the object returned by the Value property
GetValueOrDefault()
Retrieves the value of the current Nullable<T> object or the default value.
static void Main(string[] args) { Nullablei = null; Console.WriteLine(i.GetValueOrDefault()); }
GetValueOrDefault(T)
Retrieves the value of the current Nullable<T> object or the specified default value
ToString()
Returns the text representation of the value of the current Nullable<T> object.
DateTime? dt2 = DateTime.Now; Console.WriteLine(dt2.HasValue ? dt2.Value.ToString("yyyy-MM-dd hh:mm:ss") : "[N/A]");
Conversions
Explicit(Nullable<T> to T)
Explicit conversion of a Nullable<T> instance to its underlying value.
int? n = null; //int m1 = n; // Will not compile. int m2 = (int)n; // Compiles, but will create an exception if n is null. int m3 = n.Value; // Compiles, but will create an exception if n is null.
Implicit(T to Nullable<T>)
Creates a new Nullable<T> object initialized to a specified value.
int? n1 = null; int? n2; n2 = 10;
Nullable Int eg int?
Can assigned any value from -2147483648 to 2147483647, or a null value. With null an int is invalid, missing or uninitialized, no special values are needed like -1. Aliased to System.Int32 type therefore System.Int32? will do the job.
DateTime Nullable
DateTime is a struct, you get DateTime object and not reference. Declaring int cannot be null so declaring DateTime cannot be null. Adding question mark turns into nullable type which means that it can be DateTime object or null. DateTime? is equivalent to Nullable
DateTime? a = null; if(!a.HasValue) { a = DateTime.Now; if(a.HasValue) { Console.WriteLine(a.Value); } }
Casting bool
bool? cannot be used with conditionals such as if, for or while, you will need to first check the HasValue property to ensure that its value is not null.
bool? test = null; if(test ?? false) { Console.WriteLine("Hello there"); } if(!test.HasValue) { Console.WriteLine("Does not HasValue"); }
Operators (operator lifting)
The Nullable<T> struct does not define basic operators but it lifts or borrows operators from value types.
The predefined unary and binary operators and any user-defined operators that exist for value types maybe also used by nullable types. The operators will produce null value if the operands are null.. For comparisons with nullable types, will evaluate to false except != operator.
int? a = 10; int? b = null; a++; Console.WriteLine(a); -- 11 a = a * 10; Console.WriteLine(a); -- 110 a = a + b; Console.WriteLine(a); -- null
Use ?? operator to assign a nullable type to a non-nullable type
int? i = null; int j = i ?? 0; -- with multiple null types int? e = null; int? f = null; int g = e ?? f ?? -1;
In the above example, i is a nullable int and if you assign it to the non-nullable int j then it will throw a runtime exception if i is null. So to mitigate the risk of an exception, we have used the ‘??’ operator to specify that if i is null then assign 0 to j.
You can also use the == and != operators with a nullable type, as shown in the following example: if (x != null) y = x;
Note: If exactly one operand is null, the operands are unequal and if both operands are non-null, their Values are compared.
int? x = 5; int? y = 10; { bool b = x < y; // true } // The above line is equivalent to: { bool b = (x.HasValue && y.HasValue) ? (x.Value < y.Value) : false; }
Mixing nullable and non-nullable operators
You can mix and match nullable and non-nullable types due to implicit conversion.
int? a = null; int b = 2; int? c = a + b; // c is null - equivalent to a + (int?)b
Bool? with & and | Operatos
// When supplied operands of type bool?, the & and | operators treat null as an unknown // value, rather like with SQL: bool? n = null; bool? f = false; bool? t = true; Console.WriteLine (n | n); // (null) Console.WriteLine (n | f); // (null) Console.WriteLine (n | t); // True Console.WriteLine (n & n); // (null) Console.WriteLine (n & f); // False Console.WriteLine (n & t); // (null)
Benefits
It is good to use when retrieving data from database tables where fields have nulls, you can define the class as:
public struct titleAuthor { public string id; public string title; public int? royaltyper; -- can be null in database table }
Assignment Rules
Nullable type declaration must assigned a value
Access the value using NullableType.value will throw runtime exception if nullable type is null or not assigned any value.
Nullable<int> i = null; Console.WriteLine(i.Value);
Static Nullable Helper class
Comparison operators will not work against null
int? i = null; int j = 10; if (i < j) Console.WriteLine("i < j"); else if( i > 10) Console.WriteLine("i > j"); else if( i == 10) Console.WriteLine("i == j"); else Console.WriteLine("Could not compare");
Nullable static class is a helper class for Nullable types. It provides a compare method to compare nullable types. It also has a GetUnderlyingType method that returns the underlying type argument of nullable types.
int? i = null; int j = 10; if (Nullable.Compare<int>(i, j) < 0) Console.WriteLine("i < j"); else if (Nullable.Compare<int>(i, j) > 0) Console.WriteLine("i > j"); else Console.WriteLine("i = j");
Boxing Nullable Types
When T? is boxed, the value stored on heap in T and not T?. Objects based on nullable types are only boxed if the object is non-null. If the object is non-null and hasValue is true then boxing will happen and also it can be unboxed into nullable types. C# also permits the unboxing of nullable types with the as operator
object o = "string"; int? x = o as int?; Console.WriteLine (x.HasValue); // False
How to Identify a Nullable Type
Using System.Reflection namesapce to generate Type objects that represent Nullable types.
System.Type type = typeof(int?);
It is impossible to get the type at runtime using the GetType() method because the boxing operation is performed during runtime therefore it will return the Type object that represents the type.
It is useful when you want to add another state invalid or uninitialized to a value type.
Nullable Types & Null Operators (Null Coalescing Operator)
Nullable types work particularly well with the ?? operator which is equivalent to GetValueOrDefault() method. It can be used with nullable types and also with reference types. It means that "If the operand is non-null, give the to me; otherwise, give me the default value."
int? x = null; int y = x ?? 5; Console.WriteLine (y); // 5 int? a = null, b = 1, c = 2; Console.WriteLine (a ?? b ?? c); // 1 (first non-null value)
Nullable types also work well with the null-conditional operator
System.Text.StringBuilder sb = null; int? length = sb?.ToString().Length; length.Dump(); // We can combine this with the null coalescing operator to evaluate to zero instead of null: int length2 = sb?.ToString().Length ?? 0; // Evaluates to 0 if sb is null length2.Dump();
A nullable type can also be used to represent the backing field called ambient property. Ambient property, if null returns the value of its parent.
// Color is an ambient property: public class Row { /*...*/ Grid parent; Color? color; public Color Color { get { return color ?? parent.Color; } set { color = Color == parent.Color ? (Color?)null : value; } } } class Grid { /*...*/ public Color Color { get; set; } } void Main() { }