The nullvalue is very useful in C#. For any type the nullcould be used to identify whether this particular variable contains a value or not. Typical use of nullis to assign a variable nullvalue to indicate that this variable has not been initialized. Whenever we need use this, we first check whether it is nullor not, if it is null then perhaps we need to initialize and use it and if it is not then we can use it right away.
Now if we consider the same scenario for built in numeric types or struct types, then How will we represent the absence of value. In an int type all the values are valid intvalues. The moment I declare int,it contains some default value. So is it possible to use nullassignment and checking with int(or struct types)?
The answer to the above question is – No, it is not possible to assign/check with nullvalue for numeric types and struct types. So if we still need to have the possibility of checking for nullfor numeric types and structs, we need to define them as Nullabletypes.
Using the code
So let us start by looking at how we can use nullwith reference types. Let us have a simple class and nullwill represent the absence of value.
How to create and use Nullable types
If this same entity would have need defined as an struct then it would not be possible to usenullwith it.
So if we still need the object of class B to have the possibility of having null representing a null value then we need to create a Nullabletype for B. A Nullabletype is used to represent a possible missing value of a type.
A Nullabletype can be created as Nullable<T>. The T here is the type that cannot have nullvalues. The type Nullable<T>will either have a nullvalue or any possible value that T can have. So let us define a Nullabletype for the above mentioned struct and see how we can use it.
And if we need to create a Nullableint then we can do it as
Shorthand for using Nullable types
Instead of writing Nullable<T> every time, we can use the shorthand version for creating TheNullabletypes as T? t. Following code snippet shows how to use the shorthand notation to create the Nullabletypes.
How is Nullable defined
The Nullabletype is defined as a struct and this itself is a value type. Following code snippet shows the major properties and functions that we might be needing if we are using aNullabletype.
The HasValueproperty will return trueif the current Nullable<T>object has a value otherwise it will return false.
The Value property will return the value of the Nullable<T> object if the Nullable<T>.HasValue is true. if HasValuereturns false then it will throw an exception.
The first version of GetValueOrDefaultwill return the value of the contained T type if it has some value otherwise it will return the T’s default value. The second version will return the specified default value(passed as parameter) if the Nullable<T> has no value.
And finally the ToStringmethod will return the string representation of the value contained in type T.
Conversion between Nullable and non-Nullable types
Once we create a Nullabletype, we will find our self in need to convert it to and from the actual type. To understand how this conversion works, we need to look into how the conversion operators are defined in the Nullabletype.
So looking at the above function declarations, it is clear that Conversion from T to Nullableis implicit but Conversion from Nullableto T is explicit.
Boxing and Unboxing Nullable types
If we perform boxing on a T? then the the T will be boxed and not the T?. This optimization is provided by the C# itself. Also we can unbox any value and get the Nullabletype in return. This is useful when we need to check for nullafter unboxing. Following code snippet shows how the boxing and unboxing works in unison with Nullabletypes.
Null Coalescing Operator
We have already discussed the GetValueOrDefaultfunction above which will return the value of the contained T type if it has some value otherwise it will return the default value. This same thing can be achieved by using the Null coalescing operator ??. This operator is a syntactic sugar to perform the same operation as GetValueOrDefault(T defaultValue).
Operators and Nullable types
Before we finish let us look at the use of operators with Nullabletypes i.e. Operator lifting.the concept of operator lifting is that if we use Nullabletypes with operators then it could use the operators on underlying types but once it has checked for nullvalue. Though we can use onNullable types as if we are using it for the containing types, there are some things to be kept in mind.
- Unary operators: Result will be nullif the Nullabletypes value is null.
- Binary Operator: Result will be nullif any of the operands is null.
- Equality Operator: if both operands are null, result will be true. If only one of the operand isnull, it is evaluated to false. otherwise underlying types will be compared for equality.
- Relational Operator: if any operand is null, the result is false otherwise the comparison will be made on underlying type’s values.