Previous month:
August 2019
Next month:
October 2019

September 2019

C# 8: Nullable Reference Types in .NET Standard < 2.1 and .NET 4.x

By switching the LangVersion to 8.0 and setting Nullable to enable in the csproj-file we are now benefiting from the nullable reference types introduced with the latest version of C#. By enabling this new feature all type members, input and output parameters are considered to be not-null. If some members or parameters, like string value can be null then we need to put a ? at the end of the type: string? value.

For most use cases putting a ? is enough but sometimes we need more control over when a parameter is null and when it isn't. To do so we can use one of the new attributes from the namespace System.Diagnostics.CodeAnalysis, some of them are NotNullWhen and NotNullIfNotNull.

Here is an example to make the benefits of one of the attributes more clear:

[return: NotNullIfNotNull("value")]
public static string? Reverse(this string? value)
{
if (value == null)
return null;

return new String(Enumerable.Reverse(value).ToArray());
}

The NotNullIfNotNull states that if the parameter value is not null then the output will be not null as well. Thanks to the annotation we get a corresponding warning when trying to access a null reference.

string value1 = null;
var firstChar1 = value1.Reverse()[0]; // Warn: Dereference of a possibly null reference.

string value2 = "123";
var firstChar2 = value2.Reverse()[0]; // No warning

The problem is, this attributes are available in projects referencing .NET Standard 2.1 or .NET Core 3.0. So, having a class library targeting multiple frameworks like .NET Standard 2.0, .NET Standard 2.1 and .NET 4.8 we are kind of limited to the ? only, or so it seems.

The solution looks the same as with Jetbrains.Annotations, we copy the code of the required attributes into our project and make them internal:

#if !NETSTANDARD2_1

namespace System.Diagnostics.CodeAnalysis
{
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Parameter | AttributeTargets.ReturnValue, AllowMultiple = true)]
internal sealed class NotNullIfNotNullAttribute : Attribute
{
public string ParameterName { get; }

public NotNullIfNotNullAttribute(string parameterName)
{
ParameterName = parameterName;
}
}
}
#endif

The null-checks are now available in projects targeting the "older" platforms as well.