Nullable Types And Null Coalescing Operator C#

The ?? operator is also known as the null-coalescing operator. It returns the left side operand if the operand is not null else it returns the right side operand. This article explains what is nullable types, the null coalescing operator, and unique ways to use the null-coalescing operator in C#.

Contents

C# Nullables

A reference type can have an actual value of null, meaning it has no value. A value type can’t have a value of null.

For example, how would you express that some boolean value is true, false, or unknown? Regular Boolean can be only true or false.

This is why Nullables were added to the .Net Framework. A Nullable is a wrapper around a value type with a Boolean flag that it stores if the Nullable has a value set

Below is a simplified version of the support of Nullables in the .NET Framework

 1 [Serializable, StructLayout(LayoutKind.Sequential)]
 2 public struct Nullable<T> where T : struct
 3 {
 4     // These 2 fields represent the state
 5     private Boolean hasValue = false; // Assume null
 6     internal T value = default(T); // Assume all bits zero
 7     public Nullable(T value)
 8     {
 9         this.value = value;
10         this.hasValue = true;
11     }
12     public Boolean HasValue { get { return hasValue; } }
13     public T Value
14     {
15         get
16         {
17             if (!hasValue)
18             {
19                 throw new InvalidOperationException(
20                 "Nullable object must have a value.");
21             }
22             return value;
23         }
24     }
25     public T GetValueOrDefault() { return value; }
26     public T GetValueOrDefault(T defaultValue)
27     {
28         if (!HasValue) return defaultValue;
29         return value;
30     }
31     public override Boolean Equals(Object other)
32     {
33         if (!HasValue) return (other == null);
34         if (other == null) return false;
35         return value.Equals(other);
36     }
37     public override int GetHashCode()
38     {
39         if (!HasValue) return 0;
40         return value.GetHashCode();
41     }
42     public override string ToString()
43     {
44         if (!HasValue) return "";
45         return value.ToString();
46     }
47     public static implicit operator Nullable<T>(T value)
48     {
49         return new Nullable<T>(value);
50     }
51     public static explicit operator T(Nullable<T> value)
52     {
53         return value.Value;
54     }
55 }

You can use the ‘?’ operator to shorthand the syntax e.g. int?, long? instead of using Nullable.

Shorthand Syntax For Nullable Types

1 int? i = null;
2 double? d = null;

From the above definition, you can easily make out that:

  • Nullable type is also a value type.
  • Nullable Type is of struct type that holds a value type (struct) and a Boolean flag, named HasValue, to indicate whether the value is null or not.
  • Since Nullable itself is a value type, it is fairly lightweight. The size of Nullable type instance is the same as the size of containing value type plus the size of a boolean.
  • The nullable types parameter T is struct. i.e., you can use nullable type only with value types. This is quite ok because reference types can already be null. You can also use the Nullable type for your user defined struct.
  • Nullable type is not an extension in all the value types. It is a struct which contains a generic value type and a boolean flag.

This is all about Nullable types in C#. Now I am going to discuss the Null Coalescing operator in C#.

What Is Null Coalescing Operator In C#?

The ?? operator is called the null-coalescing operator. You can use it to provide a default value for nullable value types or for reference types. The operator returns the left value if it’s not null; otherwise, the right operand. Here is an example of using the operator.

1 int? x = null;
2 int y = x ?? -1;

In this case, the value of y is -1 because x is null. You can also nest the null-coalescing operator, below is an example,

1 int? x = null;
2 int? z = null;
3 int y = x ??
4         z ??
5         -1;

Of course, you can achieve the same with an if statement but the null-coalescing operator can shorten your code and improve its readability.

Null Coalescing Operators In Practical Scenarios

Let us see how to use the Null coalescing operators in practical scenarios.

Scenario 1 - Assign a Nullable type to Non-Nullable Type

Consider the following piece of code where we are assigning a nullable type to a non-nullable type.

 1 class Program
 2 {
 3     static void Main(string[] args)
 4     {
 5         int? a = null;
 6         int b = a.Value;
 7         Console.WriteLine("Value of b is {0}", b);
 8 
 9         Console.ReadLine();
10     }
11 }

In the code above, if the nullable type (in our case ‘a’) has a null value and the null value is assigned to a non-nullable type (in our case ‘b’), an exception of type InvalidOperationException is thrown.

One way to resolve this error is to use an “IF..ELSE” condition and check the value of the nullable type before assigning it to the non-nullable type

 1 class Program
 2 {
 3     static void Main(string[] args)
 4     {
 5         int? a = null;
 6         int b;
 7         if (a.HasValue)
 8             b = a.Value;
 9         else
10             b = 0;
11         Console.WriteLine("Value of b is {0}", b);
12 
13         Console.ReadLine();
14     }
15 }

The code will now compile and give you desired results. However using the null coalescing operator in such scenarios, you can create clearer code than the equivalent if-else statement, as shown below:

 1 class Program
 2 {
 3     static void Main(string[] args)
 4     {
 5         int? a = null;
 6         int b = a ?? 0;
 7         Console.WriteLine("Value of b is {0}", b);
 8 
 9         Console.ReadLine();
10     }
11 }

In the code shown above, if ‘a’ has been assigned a non-null value, then this value will be assigned to the int b. However since the nullable type ‘a’ has been assigned null, the value to the right of the operator (??) i.e. zero will be assigned to b instead.

Scenario 2 - How you can use this operator in LINQ.

 1 using System;  
 2 using System.Collections.Generic;  
 3 using System.Linq;  
 4 using System.Text;  
 5 using System.Threading.Tasks;  
 6   
 7 namespace NullCollation  
 8 {  
 9     public class Employee  
10     {  
11         public int Id { get; set; }  
12         public int age { get; set; }  
13         public string name { get; set; }  
14         public string gender { get; set; }  
15     }  
16     class Program  
17     {  
18   
19         static void Main(string[] args)  
20         {  
21             List<Employee> li = new List<Employee>();  
22             li.Add(new Employee { Id = 1, name = "Ritesh", gender = "M" });  
23             li.Add(new Employee { Id = 2, name = "sujit", gender = "M" });  
24             li.Add(new Employee { Id = 3, name = "Kabir", gender = "F" });  
25             li.Add(new Employee { Id = 4, name = null, gender = "F" });  
26             li.Add(new Employee { Id = 5, name = "Kamlesh", gender = "M" });  
27             li.Add(new Employee { Id = 6, name = "Manoj", gender = "M" });  
28   
29             var Data = from emp in li where emp.Id == 4 
30                 select new { Name = emp.name ?? "No name" };  
31   
32             foreach (var obj in Data)  
33             {  
34                 Console.WriteLine(obj.Name);  
35             }  
36             Console.ReadLine();  
37   
38         }  
39     }  
40 }

Scenario 3 - In expressions with the null-conditional operators ?. and ?[]

You can use the null-coalescing operator to provide an alternative expression to evaluate in case the result of the expression with null-conditional operations is null:

1 double SumNumbers(List<double[]> setsOfNumbers, int indexOfSetToSum)
2 {
3     return setsOfNumbers?[indexOfSetToSum]?.Sum() ?? double.NaN;
4 }
5 
6 var sum = SumNumbers(null, 0);
7 Console.WriteLine(sum);  // output: NaN

Scenario 4 - Null-conditional delegate invocation

Use the ?. operator to check if a delegate is non-null and invoke it in a thread-safe way (for example, when you raise an event), as the following code shows:

1 myDelegate?.Invoke(args)

Scenario 5 - You can use the null coalesce operator to lazy load certain properties.

 1 public class Vocabulary
 2 {
 3     private IEnumerable<string> _definitions;
 4     public IEnumerable<string> Definitions
 5     {
 6         get
 7         {
 8             return _definitions ?? (
 9                 _definitions = new List<string>
10                 {
11                     "definition 1",
12                     "definition 2",
13                     "definition 3"
14                 }
15             );
16         }
17     } 
18 }

Further Reading

  • ?. in C#: When properties might be null by Bill Wagner - In this article, Bill explains concise syntax for checking against null, and taking some default action based on the ‘null-ness’ of a variable.

  • Eliminate null-checks using arrays by Kasper B. Graversen - In this article, Kasper show a coding pattern which eliminate the need for null-checking. since null typically is used to indicate that “nothing is here” - this is essentially the semantics of an empty array. The result is shorter and easier to read code.

References

Nullable Types And Null Coalescing Operator C#
Share this

Subscribe to Code with Shadman