
C# 9 and .NET 5 – Modern Cross-Platform Development
By :

You have now seen how to store primitive values like numbers in variables. But what if a variable does not yet have a value? How can we indicate that? C# has the concept of a null
value, which can be used to indicate that a variable has not been set.
By default, value types like int
and DateTime
must always have a value, hence their name. Sometimes, for example, when reading values stored in a database that allows empty, missing, or null values, it is convenient to allow a value type to be null
. We call this a nullable value type.
You can enable this by adding a question mark as a suffix to the type when declaring a variable. Let's see an example:
Chapter02
folder, create a new folder named NullHandling
.NullHandling
folder to the Chapter02
workspace.NullHandling
project.NullHandling
folder.NullHandling
as the current project for OmniSharp.NullHandling
project, in Program.cs
, in the Main
method, add statements to declare and assign values, including null
, to int
variables, as shown in the following code:
int thisCannotBeNull = 4;
thisCannotBeNull = null; // compile error!
int? thisCouldBeNull = null;
Console.WriteLine(thisCouldBeNull);
Console.WriteLine(thisCouldBeNull.GetValueOrDefault());
thisCouldBeNull = 7;
Console.WriteLine(thisCouldBeNull);
Console.WriteLine(thisCouldBeNull.GetValueOrDefault());
0
7
7
The first line is blank because it is outputting the null
value!
The use of the null
value is so common, in so many languages, that many experienced programmers never question the need for its existence. But there are many scenarios where we could write better, simpler code if a variable is not allowed to have a null
value.
More Information: You can find out more through the following link, where the inventor of null
, Sir Charles Antony Richard Hoare, admits his mistake in a recorded hour-long talk: https://www.infoq.com/presentations/Null-References-The-Billion-Dollar-Mistake-Tony-Hoare
The most significant change to the language in C# 8.0 was the introduction of nullable and non-nullable reference types. "But wait!", you are probably thinking, "Reference types are already nullable!"
And you would be right, but in C# 8.0 and later, reference types can be configured to no longer allow the null
value by setting a file- or project-level option to enable this useful new feature. Since this is a big change for C#, Microsoft decided to make the feature opt-in.
It will take multiple years for this new C# language feature to make an impact since there are thousands of existing library packages and apps that will expect the old behavior. Even Microsoft has not had time to fully implement this new feature in all the main .NET 5 packages.
More Information: You can read the tweet about achieving 80% annotations in .NET 5 at the following link: https://twitter.com/terrajobst/status/1296566363880742917
During the transition, you can choose between several approaches for your own projects:
To enable the feature at the project level, add the following to your project file:
<PropertyGroup>
<Nullable>enable</Nullable>
</PropertyGroup>
To disable the feature at the file level, add the following to the top of a code file:
#nullable disable
To enable the feature at the file level, add the following to the top of a code file:
#nullable enable
If you enable nullable reference types and you want a reference type to be assigned the null
value, then you will have to use the same syntax as making a value type nullable, that is, adding a ?
symbol after the type declaration.
So, how do nullable reference types work? Let's look at an example. When storing information about an address, you might want to force a value for the street, city, and region, but the building can be left blank, that is, null:
NullHandling.csproj
, add an element to enable nullable reference types, as shown highlighted in the following markup:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net5.0</TargetFramework>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>
Program.cs
, at the top of the file add a statement to enable nullable reference types, as shown in the following code:
#nullable enable
Program.cs
, in the NullHandling
namespace, above the Program
class, add statements to declare an Address
class with four fields, as shown in the following code:
class Address
{
public string? Building;
public string Street;
public string City;
public string Region;
}
Street
, as shown in the following screenshot:Figure 2.6: Warning messages about non-nullable fields in the PROBLEMS window
public string Street = string.Empty;
public string City = string.Empty;
public string Region = string.Empty;
Main
, add statements to instantiate an Address
and set its properties, as shown in the following code:
var address = new Address();
address.Building = null;
address.Street = null;
address.City = "London";
address.Region = null;
Figure 2.7: Warning message about assigning null to a non-nullable field
So, this is why the new language feature is named nullable reference types. Starting with C# 8.0, unadorned reference types can become non-nullable, and the same syntax is used to make a reference type nullable as is used for value types.
More Information: You can watch a video to learn how to get rid of null reference exceptions forever at the following link: https://channel9.msdn.com/Shows/On-NET/This-is-how-you-get-rid-of-null-reference-exceptions-forever
Checking whether a nullable reference type or nullable value type variable currently contains null
is important because if you do not, a NullReferenceException
can be thrown, which results in an error. You should check for a null
value before using a nullable variable, as shown in the following code:
// check that the variable is not null before using it
if (thisCouldBeNull != null)
{
// access a member of thisCouldBeNull
int length = thisCouldBeNull.Length; // could throw exception
...
}
If you are trying to use a member of a variable that might be null
, use the null-conditional operator ?.
, as shown in the following code:
string authorName = null;
// the following throws a NullReferenceException
int x = authorName.Length;
// instead of throwing an exception, null is assigned to y
int? y = authorName?.Length;
More Information: You can read more about the null-conditional operator at the following link: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/null-conditional-operators
Sometimes you want to either assign a variable to a result or use an alternative value, such as 3
, if the variable is null
. You do this using the null-coalescing operator, ??
, as shown in the following code:
// result will be 3 if authorName?.Length is null
var result = authorName?.Length ?? 3;
Console.WriteLine(result);
More Information: You can read about the null-coalescing operator at the following link: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/null-coalescing-operator