My Favorite C# Features - Part 3: Nullability
Tags: dotnet, csharp, programming
Published: 2021-04-09 19:57:37

---
title: My Favorite C# Features - Part 3: Nullability
published: true
description: Fritz continues his series exploring C# language features by looking at the null and nullable keywords and how we can avoid the dreaded NullReferenceException
tags: dotnet, csharp, programming
series: My Favorite C# Features
//cover_image: https://direct_url_to_image.jpg
---
I'm a practical programmer.  I don't like to over-optimize my code, and I want to make it very readable for the next person who needs to work with something that I wrote.  Consequently, I sometimes leave alternate interpretations and access patterns into my code that might not always work as expected.  A great example of this is the ability to pass `null` into C# methods and trigger a different behavior.  This can lead to errors in future code where you are now accessing something that inadvertently is a `null` object.

In C# 8, the langauge designers introduced a feature called [**Nullable Reference Types**](https://docs.microsoft.com/dotnet/csharp/nullable-references?WT.mc_id=friends-0000-jefritz) that allows you to define which variables could be null and which variables should **NEVER** be null.

In this article, and as an effort to help make myself a better programmer, we're going to review the nullable Reference Types feature of C# and discuss why it is an important feature that we should start using by default in our applications.

## Why null?

As an object oriented language, C# has always had the concept of `null` in code.  null is the absence of an object, its synonymous with "nothing" and is an easy concept for folks to understand when you declare a variable.  However, this can (and most likely WILL) lead to the dreaded `NullReferenceException`, an error that indicates a `null` object was acted on unexpectedly.  

_PRO TIP:_ Sometimes, you'll hear C# programming folks refer to a `NullReferenceException` as an NRE.

```csharp
Logger myConsoleLogger = default(ILogger);
myConsoleLogger.LogInformation("Processed the data");
```

In the sample above, the `myConsoleLogger` object is declared and assigned its default value (which is null).  This would trigger a `NullReferenceException` because `myConsoleLogger` was never assigned an instance of an object.  This is a simple mistake, but it would be really nice if the compiler caught this before we even tried to run the code.  Consider a scenario like this array:

```csharp

string[] values = new string[3];
string firstValue = values[0];
Console.WriteLine(firstValue.ToLower());

```

This is going to throw a `NullReferenceException` also, because the `values` array is declared but never assigned values.  The `firstValue` variable is initialized with a `null` value on line 2 and the `ToLower()` method is then attempting to operate on a `null` object.  Once again, a simple error because the `values` array is never assigned values.

## Nullable Contexts and Compiler Warnings to the Rescue!

Some folks fear the compiler.  There's a feeling that the compiler throwing errors or emitting warnings is an intimidating practice.  I see it the other way:  The compiler is my friend telling me when I made a mistake before I attempt to run my application.  In this case, I want the compiler to tell me when I might work with a `null` object because the variables weren't initialized properly.  Let's get some help to ensure that our objects in our code are being used correctly.

By default in C#, any reference type can be assigned the `null` value.  With C# 8 and .NET Core 3.0 and later, we can define contexts in and around our projects where the compiler will perform nullability checks and raise warnings if we are potentially going to throw a `NullReferenceException`.

We can enable nullable checking on a segment of code by wrapping it with a compiler pre-processor `#nullable ` with a setting the indicates how it should behave.  Let's add nullability checking to the `Hat` class I introduced in the previous post in this series:

```csharp
#nullable enable

	public class Hat {

		public string Name { get; set; }

		public int AcquiredYear { get; set; }

		public string Theme { get; set; }

	}

#nullable restore
```

There are two pre-processor commands present in this code:  `#nullable enable` and `#nullable restore`.  The `enable` command tells the compiler to check for variables that could be inadvertently assigned null and raise a compiler warning if there are any.  Sure enough, in the `Hat` class, the string properties `Name` and `Theme` need to be initialized according to these compiler warnings:

```
warning CS8618: Non-nullable property 'Name' must contain a non-null value when exiting 
constructor. Consider declaring the property as nullable. 
warning CS8618: Non-nullable property 'Theme' must contain a non-null value when exiting constructor. Consider declaring the property as nullable.
```

This are easy fixes as I can default the values for these two properties to `string.Empty`:

```csharp

#nullable enable
public class Hat {

  public string Name { get; set; } = string.Empty;

  public int AcquiredYear { get; set; }
  
  public string Theme { get; set; } = string.Empty;

}
#nullable restore

```

The compiler warnings go away, and I am a happy developer.  If I try to define a `Hat` and assign `null` to these fields, will the compiler catch it?

```csharp
var newHat = new Hat { 
  Name="Phillies 80's Maroon", 
  AcquiredYear=1985, 
  Theme=null 
};
```

This code DOES compile with no warnings.  Why?  The `#nullable` compiler directive is set on the `Hat` class, not the construction of the `newHat` variable.  In order to protect more of our code, we need to expand the nullable check's scope to include more of our code.

```csharp

#nullable enable

var newHat = new Hat { 
  Name="Phillies 80's Maroon", 
  AcquiredYear=1985, 
  Theme=null 
};

#nullable restore

```

This raises the appropriate compiler warning:

```
warning CS8625: Cannot convert null literal to non-nullable reference type.
```

Let's review quickly:  these are ONLY compiler warnings.  In fact, this code will run and not produce any errors.

## Declaring a Reference Type as Nullable

I can also tell the compiler that it's ok if one of these reference values is assigned null by attaching a `?` to the end of it's variable declaration:

```csharp

public class Hat {

  public string? Name { get; set; }

  public int AcquiredYear { get; set; }

  public string Theme { get; set; } = string.Empty;
}

```

With this change, the `Name` of the hat is allowed to be assigned `null` regardless of the Nullable context around the class.

## Project-wide Nullable Checking

What if I want to roll-out this compiler interaction across my ENTIRE project.  You can add an entry to your project file that indicates nullable checking should be enabled with the `Nullable` element:

```xml
<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net5.0</TargetFramework>
    <Nullable>enable</Nullable>
  </PropertyGroup>

</Project>
```

We can now remove the `#nullable` directives from the `Hat` class and I'll receive the same compiler warnings without writing more code.

## Disable Nullable Checking

What if I have an application that is configured with the `Nullable` entry in the project file, and I want to relax the checking on various sections of my application?

Similar to before, we can add a processor directive to our code that disables null checking:

```csharp

#nullable disable

var newHat = new Hat { 
  Name="Phillies 80's Maroon", 
  AcquiredYear=1985, 
  Theme=null 
};

#nullable restore

```

Now we're talking...  I can enforce the better developer behavior by adding the Nullable check to my project file, and those developers that want to take the risk of assigning and working with `null` can wrap their code with the processor to remove the warnings.

## The Final Step

Warnings are just silly yellow text the compiler emits that tells us we MIGHT have a concern in our project.  Did you know that you can turn up the importance of this warnings, converting them to errors the compiler emits and ensuring that you write better code?  Add the `TreatWarningsAsErrors` element to your project file and those pesky warnings become a real problem that blocks your project from compiling properly:

```xml
<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net5.0</TargetFramework>
    <Nullable>enable</Nullable>
    <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
  </PropertyGroup>

</Project>
```

Now our project team will be forced to treat `null` values with more respect.

## Summary

The ability to assign and work with the `null` value is valuable in C#, but can be misused and lead to errors in our running applications.  Let's get some help from the compiler to make handling of `null` values easier and clearer when we're building our projects.

Did you know, I host a weekly live stream on the [Visual Studio Twitch channel](https://twitch.tv/visualstudio) teaching the basics of C#? Tune in on Mondays at 9a ET / 1300 UTC for two hours of learning in a beginner-friendly Q+A format with demos and sample code you can download.

Looking to get started learning C#? Checkout our [free on-demand courses on Microsoft Learn!](https://docs.microsoft.com/users/dotnet/collections/yz26f8y64n7k07?WT.mc_id=friends-0000-jefritz)