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.