Nullable reference types are now enabled by default on projects created with Visual Studio 2022, so let’s have a quick look at them…
Enabling nullable reference type checking
By default nullable reference types were disabled prior to Visual Studio 2022, so would need enable them at a project or file level. Enabling in the project means adding the following to the .csproj file
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net5.0</TargetFramework>
<Nullable>enable</Nullable>
</PropertyGroup>
If you prefer to enable at a file level then simply add the following to the top of each file
#nullable enable
Now what?
So once you’ve enabled nullable reference type checking, especially if on a legacy code base, be prepared for warnings such as
- warning CS8625: Cannot convert null literal to non-nullable reference type.
- warning CS8604: Possible null reference argument for parameter ‘s’ in ‘void Program.SetName(string s)’.
- warning CS8602: Dereference of a possibly null reference.
I’m sure there are plenty of other warnings, but you get the idea.
Basically what we’re ask the compiler to do is tell us when we might have the potential to be passing a null into a function etc. and highlight the potential issue with a warning. In other words we now need to mark reference types as nullable so the compiler knows we’re expecting a null and in situations where we’re not using a nullable reference type we’ll be warned.
Let’s see some example code. First off, if you default arguments to null, for example
public void SetName(string name = null)
{
// do something
}
This will result in the warning >warning CS8625: Cannot convert null literal to non-nullable reference type.. All we need to do is tell the compiler we’re expecting a null, by making the argument nullable, i.e. add the ? to the type just like nullable value types.
public void SetName(string? name = null)
{
// do something
}
Any usage of the variable name will now expect a null check, so if we compile the following
public void SetName(string? name = null)
{
Console.WriteLine(name.Length);
}
as you’d imagine, the compiler will issue a warning here, in this case warning CS8602: Dereference of a possibly null reference., so obviously we have the potential of a null reference exception here, so adding a conditional check like this will fix that
static void SetName(string? name = null)
{
if (name != null)
{
Console.WriteLine(name.Length);
}
}
In some situations you may in fact know a variable/argument is not null – in TypeScript it’s not unusual to find the transpiler getting a little confused in which case we use the null-forgiving operator simply an !, so whilst the SetName method, as it stands ofcourse can be null, what if we remove the optional argument and expect all callers of the SetName method – for example maybe it’s a private method and we know each caller must check for null first anyway, then we use the following
static void SetName(string? name)
{
Console.WriteLine(name!.Length);
}
We’re basically saying, by using name!. we know the value is not null. This example is a little contrived because we could just change the string? to string and not require the !, but you get the idea.